influxdb-rails 1.0.0.beta1 → 1.0.0.beta2
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +6 -0
- data/README.md +75 -9
- data/Rakefile +17 -18
- data/influxdb-rails.gemspec +4 -2
- data/lib/influxdb/rails/configuration.rb +15 -0
- data/lib/influxdb/rails/instrumentation.rb +4 -4
- data/lib/influxdb/rails/middleware/render_subscriber.rb +20 -0
- data/lib/influxdb/rails/middleware/request_subscriber.rb +51 -0
- data/lib/influxdb/rails/middleware/simple_subscriber.rb +46 -0
- data/lib/influxdb/rails/middleware/sql_subscriber.rb +32 -0
- data/lib/influxdb/rails/middleware/subscriber.rb +38 -0
- data/lib/influxdb/rails/railtie.rb +20 -12
- data/lib/influxdb/rails/sql/normalizer.rb +27 -0
- data/lib/influxdb/rails/sql/query.rb +30 -0
- data/lib/influxdb/rails/version.rb +1 -1
- data/lib/influxdb-rails.rb +9 -47
- data/spec/integration/metrics_spec.rb +17 -10
- data/spec/support/rails4/app.rb +16 -2
- data/spec/support/rails5/app.rb +15 -2
- data/spec/support/views/widgets/_item.html.erb +1 -0
- data/spec/support/views/widgets/index.html.erb +5 -0
- data/spec/unit/configuration_spec.rb +17 -0
- data/spec/unit/influxdb_rails_spec.rb +7 -93
- data/spec/unit/middleware/render_subscriber_spec.rb +90 -0
- data/spec/unit/middleware/request_subscriber_spec.rb +106 -0
- data/spec/unit/middleware/sql_subscriber_spec.rb +79 -0
- data/spec/unit/sql/normalizer_spec.rb +15 -0
- data/spec/unit/sql/query_spec.rb +28 -0
- metadata +63 -8
data/lib/influxdb-rails.rb
CHANGED
@@ -2,6 +2,10 @@ require "net/http"
|
|
2
2
|
require "net/https"
|
3
3
|
require "rubygems"
|
4
4
|
require "socket"
|
5
|
+
require "influxdb/rails/middleware/render_subscriber"
|
6
|
+
require "influxdb/rails/middleware/request_subscriber"
|
7
|
+
require "influxdb/rails/middleware/sql_subscriber"
|
8
|
+
require "influxdb/rails/sql/query"
|
5
9
|
require "influxdb/rails/version"
|
6
10
|
require "influxdb/rails/logger"
|
7
11
|
require "influxdb/rails/exception_presenter"
|
@@ -69,11 +73,14 @@ module InfluxDB
|
|
69
73
|
env = influxdb_request_data if env.empty? && defined? influxdb_request_data
|
70
74
|
exception_presenter = ExceptionPresenter.new(ex, env)
|
71
75
|
log :info, "Exception: #{exception_presenter.to_json[0..512]}..."
|
76
|
+
tags = configuration.tags_middleware.call(
|
77
|
+
exception_presenter.context.merge(exception_presenter.dimensions)
|
78
|
+
)
|
72
79
|
|
73
80
|
client.write_point \
|
74
81
|
configuration.series_name_for_exceptions,
|
75
82
|
values: exception_presenter.values.merge(ts: timestamp),
|
76
|
-
tags:
|
83
|
+
tags: tags,
|
77
84
|
timestamp: timestamp
|
78
85
|
rescue StandardError => ex
|
79
86
|
log :info, "[InfluxDB::Rails] Something went terribly wrong." \
|
@@ -81,56 +88,11 @@ module InfluxDB
|
|
81
88
|
end
|
82
89
|
alias transmit report_exception
|
83
90
|
|
84
|
-
def handle_action_controller_metrics(_name, start, finish, _id, payload)
|
85
|
-
tags = {
|
86
|
-
method: "#{payload[:controller]}##{payload[:action]}",
|
87
|
-
status: payload[:status],
|
88
|
-
format: payload[:format],
|
89
|
-
http_method: payload[:method],
|
90
|
-
path: payload[:path],
|
91
|
-
server: Socket.gethostname,
|
92
|
-
app_name: configuration.application_name,
|
93
|
-
}.reject { |_, value| value.nil? }
|
94
|
-
|
95
|
-
ts = convert_timestamp(finish.utc)
|
96
|
-
|
97
|
-
begin
|
98
|
-
{
|
99
|
-
configuration.series_name_for_controller_runtimes => ((finish - start) * 1000).ceil,
|
100
|
-
configuration.series_name_for_view_runtimes => (payload[:view_runtime] || 0).ceil,
|
101
|
-
configuration.series_name_for_db_runtimes => (payload[:db_runtime] || 0).ceil,
|
102
|
-
}.each do |series_name, value|
|
103
|
-
client.write_point series_name, values: { value: value }, tags: tags, timestamp: ts
|
104
|
-
end
|
105
|
-
rescue StandardError => e
|
106
|
-
log :error, "[InfluxDB::Rails] Unable to write points: #{e.message}"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
91
|
# rubocop:enable Metrics/MethodLength
|
111
92
|
# rubocop:enable Metrics/AbcSize
|
112
93
|
|
113
|
-
TIMESTAMP_CONVERSIONS = {
|
114
|
-
"ns" => 1e9.to_r,
|
115
|
-
nil => 1e9.to_r,
|
116
|
-
"u" => 1e6.to_r,
|
117
|
-
"ms" => 1e3.to_r,
|
118
|
-
"s" => 1.to_r,
|
119
|
-
"m" => 1.to_r / 60,
|
120
|
-
"h" => 1.to_r / 60 / 60,
|
121
|
-
}.freeze
|
122
|
-
private_constant :TIMESTAMP_CONVERSIONS
|
123
|
-
|
124
|
-
def convert_timestamp(time)
|
125
|
-
conv = TIMESTAMP_CONVERSIONS.fetch(configuration.time_precision) do
|
126
|
-
raise "Invalid time precision: #{configuration.time_precision}"
|
127
|
-
end
|
128
|
-
|
129
|
-
(time.to_r * conv).to_i
|
130
|
-
end
|
131
|
-
|
132
94
|
def current_timestamp
|
133
|
-
|
95
|
+
InfluxDB.now(configuration.time_precision)
|
134
96
|
end
|
135
97
|
|
136
98
|
def ignorable_exception?(ex)
|
@@ -1,21 +1,28 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + "/integration_helper")
|
2
2
|
|
3
|
-
RSpec.describe
|
3
|
+
RSpec.describe WidgetsController, type: :controller do
|
4
|
+
render_views
|
5
|
+
|
4
6
|
before do
|
5
|
-
InfluxDB::Rails.
|
6
|
-
config.ignored_environments = %w[development]
|
7
|
-
end
|
7
|
+
allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_environments).and_return(%w[development])
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "in a normal request" do
|
11
|
-
it "should
|
12
|
-
expect(InfluxDB::Rails).to receive(:
|
13
|
-
get
|
11
|
+
it "should result in attempts to write metrics via the client" do
|
12
|
+
expect(InfluxDB::Rails.client).to receive(:write_point).exactly(6).times
|
13
|
+
get :index
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
context "with sql reports enabled" do
|
17
|
+
before do
|
18
|
+
allow_any_instance_of(InfluxDB::Rails::Middleware::SqlSubscriber).to receive(:series_name).and_return("rails.sql")
|
19
|
+
get :index # to not count ActiveRecord initialization
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should result in attempts to write metrics via the client" do
|
23
|
+
expect(InfluxDB::Rails.client).to receive(:write_point).exactly(7).times
|
24
|
+
get :index
|
25
|
+
end
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
data/spec/support/rails4/app.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require "action_controller/railtie"
|
2
|
+
require "active_record"
|
2
3
|
|
3
4
|
app = Class.new(Rails::Application)
|
5
|
+
app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
|
4
6
|
app.config.secret_token = "1234567890abcdef1234567890abcdef"
|
5
7
|
app.config.session_store :cookie_store, key: "_myapp_session"
|
6
8
|
app.config.active_support.deprecation = :log
|
7
9
|
app.config.eager_load = false
|
8
|
-
app.config.root =
|
10
|
+
app.config.root = __dir__
|
9
11
|
Rails.backtrace_cleaner.remove_silencers!
|
10
12
|
app.initialize!
|
11
13
|
|
@@ -16,10 +18,22 @@ end
|
|
16
18
|
InfluxDB::Rails.configure do |config|
|
17
19
|
end
|
18
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
|
19
31
|
class ApplicationController < ActionController::Base; end
|
20
32
|
class WidgetsController < ApplicationController
|
33
|
+
prepend_view_path File.join(__dir__, "..", "views")
|
34
|
+
|
21
35
|
def index
|
22
|
-
|
36
|
+
Widget.create!(title: "test")
|
23
37
|
end
|
24
38
|
|
25
39
|
def new
|
data/spec/support/rails5/app.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "action_controller/railtie"
|
2
|
+
require "active_record"
|
2
3
|
|
3
4
|
app = Class.new(Rails::Application)
|
4
5
|
app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
|
@@ -6,7 +7,7 @@ app.config.secret_token = "1234567890abcdef1234567890abcdef"
|
|
6
7
|
app.config.session_store :cookie_store, key: "_myapp_session"
|
7
8
|
app.config.active_support.deprecation = :log
|
8
9
|
app.config.eager_load = false
|
9
|
-
app.config.root =
|
10
|
+
app.config.root = __dir__
|
10
11
|
Rails.backtrace_cleaner.remove_silencers!
|
11
12
|
app.initialize!
|
12
13
|
|
@@ -17,10 +18,22 @@ end
|
|
17
18
|
InfluxDB::Rails.configure do |config|
|
18
19
|
end
|
19
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
|
20
31
|
class ApplicationController < ActionController::Base; end
|
21
32
|
class WidgetsController < ApplicationController
|
33
|
+
prepend_view_path File.join(__dir__, "..", "views")
|
34
|
+
|
22
35
|
def index
|
23
|
-
|
36
|
+
Widget.create!(title: "test")
|
24
37
|
end
|
25
38
|
|
26
39
|
def new
|
@@ -0,0 +1 @@
|
|
1
|
+
<div>item</div
|
@@ -105,4 +105,21 @@ RSpec.describe InfluxDB::Rails::Configuration do
|
|
105
105
|
expect(InfluxDB::Rails.configuration.rails_app_name).to eq("my-app")
|
106
106
|
end
|
107
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
|
108
125
|
end
|
@@ -9,101 +9,15 @@ RSpec.describe InfluxDB::Rails do
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
describe ".handle_action_controller_metrics" do
|
13
|
-
let(:start) { Time.at(1_517_567_368) }
|
14
|
-
let(:finish) { Time.at(1_517_567_370) }
|
15
|
-
let(:payload) { { view_runtime: 2, db_runtime: 2, controller: "MyController", action: "show", method: "GET", format: "*/*", path: "/posts", status: 200 } }
|
16
|
-
let(:data) do
|
17
|
-
{
|
18
|
-
values: {
|
19
|
-
value: 2
|
20
|
-
},
|
21
|
-
tags: {
|
22
|
-
method: "MyController#show",
|
23
|
-
status: 200,
|
24
|
-
format: "*/*",
|
25
|
-
http_method: "GET",
|
26
|
-
path: "/posts",
|
27
|
-
server: Socket.gethostname,
|
28
|
-
app_name: "my-rails-app",
|
29
|
-
},
|
30
|
-
timestamp: 1_517_567_370_000
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
context "application_name is set" do
|
35
|
-
it "sends metrics with taggings and timestamps" do
|
36
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
37
|
-
"rails.controller", data.merge(values: { value: 2000 })
|
38
|
-
)
|
39
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.view", data)
|
40
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.db", data)
|
41
|
-
|
42
|
-
described_class.handle_action_controller_metrics("unused", start, finish, "unused", payload)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context "application_name is nil" do
|
47
|
-
before do
|
48
|
-
InfluxDB::Rails.configure do |config|
|
49
|
-
config.application_name = nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
it "does not add the app_name tag to metrics" do
|
54
|
-
tags = {
|
55
|
-
method: "MyController#show",
|
56
|
-
status: 200,
|
57
|
-
format: "*/*",
|
58
|
-
http_method: "GET",
|
59
|
-
path: "/posts",
|
60
|
-
server: Socket.gethostname,
|
61
|
-
}
|
62
|
-
|
63
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
64
|
-
"rails.controller", data.merge(values: { value: 2000 }, tags: tags)
|
65
|
-
)
|
66
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.view", data.merge(tags: tags))
|
67
|
-
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.db", data.merge(tags: tags))
|
68
|
-
|
69
|
-
described_class.handle_action_controller_metrics("unused", start, finish, "unused", payload)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe ".convert_timestamp" do
|
75
|
-
let(:sometime) { Time.parse("2017-12-11 16:20:29.111222333 UTC") }
|
76
|
-
let(:configuration) { double("Configuration") }
|
77
|
-
before { allow(InfluxDB::Rails).to receive(:configuration).and_return configuration }
|
78
|
-
|
79
|
-
{
|
80
|
-
"ns" => 1_513_009_229_111_222_333,
|
81
|
-
nil => 1_513_009_229_111_222_333,
|
82
|
-
"u" => 1_513_009_229_111_222,
|
83
|
-
"ms" => 1_513_009_229_111,
|
84
|
-
"s" => 1_513_009_229,
|
85
|
-
"m" => 25_216_820,
|
86
|
-
"h" => 420_280,
|
87
|
-
}.each do |precision, converted_value|
|
88
|
-
it "should return the timestamp in nanoseconds when precision is #{precision.inspect}" do
|
89
|
-
allow(configuration).to receive(:time_precision).and_return(precision)
|
90
|
-
expect(InfluxDB::Rails.convert_timestamp(sometime)).to eq(converted_value)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should raise an excpetion when precision is unrecognized" do
|
95
|
-
allow(configuration).to receive(:time_precision).and_return("whatever")
|
96
|
-
expect { InfluxDB::Rails.convert_timestamp(sometime) }
|
97
|
-
.to raise_exception(/invalid time precision.*whatever/i)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
12
|
describe ".current_timestamp" do
|
13
|
+
let(:timestamp) { 1_513_009_229_111 }
|
14
|
+
|
102
15
|
it "should return the current timestamp in the configured precision" do
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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)
|
107
21
|
end
|
108
22
|
end
|
109
23
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe InfluxDB::Rails::Middleware::RenderSubscriber do
|
4
|
+
let(:config) { InfluxDB::Rails::Configuration.new }
|
5
|
+
let(:logger) { double(:logger) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(config).to receive(:application_name).and_return("my-rails-app")
|
9
|
+
allow(config).to receive(:ignored_environments).and_return([])
|
10
|
+
allow(config).to receive(:time_precision).and_return("ms")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".call" do
|
14
|
+
let(:start_time) { Time.at(1_517_567_368) }
|
15
|
+
let(:finish_time) { Time.at(1_517_567_370) }
|
16
|
+
let(:series_name) { "series_name" }
|
17
|
+
let(:payload) { { identifier: "index.html", count: 43, cache_hits: 42 } }
|
18
|
+
let(:result) do
|
19
|
+
{
|
20
|
+
values: {
|
21
|
+
value: 2000
|
22
|
+
},
|
23
|
+
tags: {
|
24
|
+
filename: "index.html",
|
25
|
+
location: "Foo#bar",
|
26
|
+
count: 43,
|
27
|
+
cache_hits: 42
|
28
|
+
},
|
29
|
+
timestamp: 1_517_567_370_000
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
subject { described_class.new(config, series_name) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
Thread.current[:_influxdb_rails_controller] = "Foo"
|
37
|
+
Thread.current[:_influxdb_rails_action] = "bar"
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
Thread.current[:_influxdb_rails_action] = nil
|
42
|
+
Thread.current[:_influxdb_rails_controller] = nil
|
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, result
|
49
|
+
)
|
50
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with empty tags" do
|
54
|
+
before do
|
55
|
+
payload[:count] = nil
|
56
|
+
result[:tags].delete(:count)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not write empty tags" do
|
60
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
61
|
+
series_name, result
|
62
|
+
)
|
63
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "disabled" do
|
68
|
+
subject { described_class.new(config, nil) }
|
69
|
+
|
70
|
+
it "does not write a data point" do
|
71
|
+
expect_any_instance_of(InfluxDB::Client).not_to receive(:write_point)
|
72
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "unsuccessfully" do
|
78
|
+
before do
|
79
|
+
allow(config).to receive(:logger).and_return(logger)
|
80
|
+
InfluxDB::Rails.configuration = config
|
81
|
+
end
|
82
|
+
|
83
|
+
it "does log exceptions" do
|
84
|
+
allow_any_instance_of(InfluxDB::Client).to receive(:write_point).and_raise("boom")
|
85
|
+
expect(logger).to receive(:error).with(/boom/)
|
86
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe InfluxDB::Rails::Middleware::RequestSubscriber do
|
4
|
+
let(:config) { InfluxDB::Rails::Configuration.new }
|
5
|
+
|
6
|
+
before do
|
7
|
+
allow(config).to receive(:time_precision).and_return("ms")
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { described_class.new(config) }
|
11
|
+
|
12
|
+
describe "#call" do
|
13
|
+
let(:start) { Time.at(1_517_567_368) }
|
14
|
+
let(:finish) { Time.at(1_517_567_370) }
|
15
|
+
let(:payload) { { view_runtime: 2, db_runtime: 2, controller: "MyController", action: "show", method: "GET", format: "*/*", status: 200 } }
|
16
|
+
let(:data) do
|
17
|
+
{
|
18
|
+
values: {
|
19
|
+
value: 2
|
20
|
+
},
|
21
|
+
tags: {
|
22
|
+
method: "MyController#show",
|
23
|
+
status: 200,
|
24
|
+
format: "*/*",
|
25
|
+
http_method: "GET",
|
26
|
+
server: Socket.gethostname,
|
27
|
+
app_name: "my-rails-app",
|
28
|
+
},
|
29
|
+
timestamp: 1_517_567_370_000
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
context "application_name is set" do
|
34
|
+
before do
|
35
|
+
allow(config).to receive(:application_name).and_return("my-rails-app")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sends metrics with taggings and timestamps" do
|
39
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
40
|
+
"rails.controller", data.merge(values: { value: 2000 })
|
41
|
+
)
|
42
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.view", data)
|
43
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.db", data)
|
44
|
+
|
45
|
+
subject.call("unused", start, finish, "unused", payload)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when tags_middleware is overwritten" do
|
49
|
+
before do
|
50
|
+
allow(config).to receive(:tags_middleware).and_return(tags_middleware)
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:tags_middleware) { ->(tags) { tags.merge(static: "value") } }
|
54
|
+
|
55
|
+
it "processes tags throught the middleware" do
|
56
|
+
tags = data[:tags].merge(static: "value")
|
57
|
+
|
58
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.controller", include(tags: tags))
|
59
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.view", include(tags: tags))
|
60
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.db", include(tags: tags))
|
61
|
+
|
62
|
+
subject.call("unused", start, finish, "unused", payload)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "application_name is nil" do
|
68
|
+
before do
|
69
|
+
allow(config).to receive(:application_name).and_return(nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "does not add the app_name tag to metrics" do
|
73
|
+
tags = {
|
74
|
+
method: "MyController#show",
|
75
|
+
status: 200,
|
76
|
+
format: "*/*",
|
77
|
+
http_method: "GET",
|
78
|
+
server: Socket.gethostname,
|
79
|
+
}
|
80
|
+
|
81
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
82
|
+
"rails.controller", data.merge(values: { value: 2000 }, tags: tags)
|
83
|
+
)
|
84
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.view", data.merge(tags: tags))
|
85
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with("rails.db", data.merge(tags: tags))
|
86
|
+
|
87
|
+
subject.call("unused", start, finish, "unused", payload)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "not successfull" do
|
92
|
+
let(:logger) { double(:logger) }
|
93
|
+
|
94
|
+
before do
|
95
|
+
allow(config).to receive(:logger).and_return(logger)
|
96
|
+
InfluxDB::Rails.configuration = config
|
97
|
+
end
|
98
|
+
|
99
|
+
it "does log an error" do
|
100
|
+
allow_any_instance_of(InfluxDB::Client).to receive(:write_point).and_raise("boom")
|
101
|
+
expect(logger).to receive(:error).with(/boom/)
|
102
|
+
subject.call("name", start, finish, "id", payload)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe InfluxDB::Rails::Middleware::SqlSubscriber do
|
4
|
+
let(:config) { InfluxDB::Rails::Configuration.new }
|
5
|
+
let(:logger) { double(:logger) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(config).to receive(:application_name).and_return("my-rails-app")
|
9
|
+
allow(config).to receive(:ignored_environments).and_return([])
|
10
|
+
allow(config).to receive(:time_precision).and_return("ms")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".call" do
|
14
|
+
let(:start_time) { Time.at(1_517_567_368) }
|
15
|
+
let(:finish_time) { Time.at(1_517_567_370) }
|
16
|
+
let(:series_name) { "series_name" }
|
17
|
+
let(:payload) { { sql: "SELECT * FROM POSTS WHERE id = 1", name: "Post Load", binds: %w[1 2 3] } }
|
18
|
+
let(:result) do
|
19
|
+
{
|
20
|
+
values: {
|
21
|
+
value: 2000,
|
22
|
+
sql: "SELECT * FROM POSTS WHERE id = xxx"
|
23
|
+
},
|
24
|
+
tags: {
|
25
|
+
location: "Foo#bar",
|
26
|
+
operation: "SELECT",
|
27
|
+
class_name: "Post",
|
28
|
+
name: "Post Load",
|
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
|
+
Thread.current[:_influxdb_rails_controller] = "Foo"
|
38
|
+
Thread.current[:_influxdb_rails_action] = "bar"
|
39
|
+
end
|
40
|
+
|
41
|
+
after do
|
42
|
+
Thread.current[:_influxdb_rails_action] = nil
|
43
|
+
Thread.current[:_influxdb_rails_controller] = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
context "successfully" do
|
47
|
+
it "writes to InfluxDB" do
|
48
|
+
expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
|
49
|
+
series_name, result
|
50
|
+
)
|
51
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with not relevant queries" do
|
55
|
+
before do
|
56
|
+
payload[:sql] = "SHOW FULL FIELDS FROM `users`"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not write to InfluxDB" do
|
60
|
+
expect_any_instance_of(InfluxDB::Client).not_to receive(:write_point)
|
61
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "unsuccessfully" do
|
67
|
+
before do
|
68
|
+
allow(config).to receive(:logger).and_return(logger)
|
69
|
+
InfluxDB::Rails.configuration = config
|
70
|
+
end
|
71
|
+
|
72
|
+
it "does log exceptions" do
|
73
|
+
allow_any_instance_of(InfluxDB::Client).to receive(:write_point).and_raise("boom")
|
74
|
+
expect(logger).to receive(:error).with(/boom/)
|
75
|
+
subject.call("name", start_time, finish_time, "id", payload)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe InfluxDB::Rails::Sql::Normalizer do
|
4
|
+
describe "#perform" do
|
5
|
+
it { expect(described_class.new("SELECT * FROM posts WHERE id = 1").perform).to eq("SELECT * FROM posts WHERE id = xxx") }
|
6
|
+
it { expect(described_class.new("SELECT * FROM posts WHERE id = 1".freeze).perform).to eq("SELECT * FROM posts WHERE id = xxx") }
|
7
|
+
it { expect(described_class.new("SELECT * FROM posts LIMIT 10").perform).to eq("SELECT * FROM posts LIMIT xxx") }
|
8
|
+
it { expect(described_class.new("SELECT * FROM posts OFFSET 10").perform).to eq("SELECT * FROM posts OFFSET xxx") }
|
9
|
+
it { expect(described_class.new("SELECT * FROM posts WHERE name LIKE '%foobar%'").perform).to eq("SELECT * FROM posts WHERE name LIKE xxx") }
|
10
|
+
it { expect(described_class.new("SELECT * FROM posts WHERE id IN (1,2,3)").perform).to eq("SELECT * FROM posts WHERE id IN (xxx)") }
|
11
|
+
it { expect(described_class.new("SELECT * FROM products WHERE price BETWEEN 10 AND 20").perform).to eq("SELECT * FROM products WHERE price BETWEEN xxx AND xxx") }
|
12
|
+
it { expect(described_class.new("INSERT INTO products (title, price) VALUES ('Computer', 100)").perform).to eq("INSERT INTO products (title, price) VALUES (xxx)") }
|
13
|
+
it { expect(described_class.new(" SELECT * FROM POSTS ").perform).to eq("SELECT * FROM POSTS") }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe InfluxDB::Rails::Sql::Query do
|
4
|
+
let(:payload) do
|
5
|
+
{
|
6
|
+
sql: "select * from users where user_id = 42;",
|
7
|
+
name: "User Load",
|
8
|
+
}
|
9
|
+
end
|
10
|
+
subject { described_class.new(payload) }
|
11
|
+
|
12
|
+
describe "#class_name" do
|
13
|
+
it { expect(subject.class_name).to eq("User") }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#operation" do
|
17
|
+
it { expect(subject.operation).to eq("SELECT") }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#track?" do
|
21
|
+
it { expect(described_class.new(sql: "INSERT").track?).to be true }
|
22
|
+
it { expect(described_class.new(sql: "UPDATE").track?).to be true }
|
23
|
+
it { expect(described_class.new(sql: "SELECT").track?).to be true }
|
24
|
+
it { expect(described_class.new(sql: "DELETE").track?).to be true }
|
25
|
+
it { expect(described_class.new(sql: "SCHEMA").track?).to be false }
|
26
|
+
it { expect(described_class.new(sql: "BEGIN").track?).to be false }
|
27
|
+
end
|
28
|
+
end
|