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
@@ -1,41 +1,25 @@
1
1
  module InfluxDB
2
2
  module Rails
3
- class Context # rubocop:disable Style/Documentation
4
- def controller
5
- Thread.current[:_influxdb_rails_controller]
6
- end
7
-
8
- def controller=(value)
9
- Thread.current[:_influxdb_rails_controller] = value
10
- end
11
-
12
- def action
13
- Thread.current[:_influxdb_rails_action]
14
- end
15
-
16
- def action=(value)
17
- Thread.current[:_influxdb_rails_action] = value
3
+ class Context
4
+ def reset
5
+ Thread.current[:_influxdb_rails_tags] = {}
6
+ Thread.current[:_influxdb_rails_values] = {}
18
7
  end
19
8
 
20
- def location
21
- [
22
- controller,
23
- action,
24
- ].reject(&:blank?).join("#")
9
+ def tags
10
+ Thread.current[:_influxdb_rails_tags].to_h
25
11
  end
26
12
 
27
- def reset
28
- Thread.current[:_influxdb_rails_controller] = nil
29
- Thread.current[:_influxdb_rails_action] = nil
30
- Thread.current[:_influxdb_rails_tags] = nil
13
+ def tags=(tags)
14
+ Thread.current[:_influxdb_rails_tags] = self.tags.merge(tags)
31
15
  end
32
16
 
33
- def tags
34
- Thread.current[:_influxdb_rails_tags] || {}
17
+ def values
18
+ Thread.current[:_influxdb_rails_values].to_h
35
19
  end
36
20
 
37
- def tags=(tags)
38
- Thread.current[:_influxdb_rails_tags] = tags
21
+ def values=(values)
22
+ Thread.current[:_influxdb_rails_values] = self.values.merge(values)
39
23
  end
40
24
  end
41
25
  end
@@ -0,0 +1,48 @@
1
+ require_relative "../test_client"
2
+ require "launchy"
3
+
4
+ module InfluxDB
5
+ module Rails
6
+ module Matchers
7
+ def expect_metric(name: "rails", **options)
8
+ expect(metrics).to include(
9
+ a_hash_including(options.merge(name: name))
10
+ )
11
+ end
12
+
13
+ def expect_no_metric(name: "rails", **options)
14
+ expect(metrics).not_to include(
15
+ a_hash_including(options.merge(name: name))
16
+ )
17
+ end
18
+
19
+ def save_and_open_metrics
20
+ dir = File.join(File.dirname(__FILE__), "..", "..", "tmp")
21
+ FileUtils.mkdir_p(dir)
22
+ file_path = File.join(dir, "metrics.json")
23
+ output = JSON.pretty_generate(metrics)
24
+ File.write(file_path, output, mode: "wb")
25
+ ::Launchy.open(file_path)
26
+ end
27
+
28
+ def metrics
29
+ TestClient.metrics
30
+ end
31
+
32
+ RSpec.configure do |config|
33
+ config.before :each do
34
+ InfluxDB::Rails.instance_variable_set :@configuration, nil
35
+ InfluxDB::Rails.configure
36
+
37
+ allow(InfluxDB::Rails).to receive(:client).and_return(InfluxDB::Rails::TestClient.new)
38
+ allow_any_instance_of(InfluxDB::Rails::Configuration)
39
+ .to receive(:ignored_environments).and_return(%w[development])
40
+
41
+ InfluxDB::Rails::TestClient.metrics.clear
42
+ end
43
+
44
+ config.include InfluxDB::Rails::Matchers
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ require "influxdb/rails/values"
2
+ require "influxdb/rails/tags"
3
+
4
+ module InfluxDB
5
+ module Rails
6
+ class Metric
7
+ def initialize(configuration:, timestamp:, tags: {}, values: {})
8
+ @configuration = configuration
9
+ @timestamp = timestamp
10
+ @tags = tags
11
+ @values = values
12
+ end
13
+
14
+ def write
15
+ client.write_point configuration.measurement_name, options
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :configuration, :tags, :values, :timestamp
21
+
22
+ def options
23
+ {
24
+ values: Values.new(values: values).to_h,
25
+ tags: Tags.new(tags: tags, config: configuration).to_h,
26
+ timestamp: timestamp_with_precision,
27
+ }
28
+ end
29
+
30
+ def timestamp_with_precision
31
+ InfluxDB.convert_timestamp(timestamp.utc, configuration.client.time_precision)
32
+ end
33
+
34
+ def client
35
+ InfluxDB::Rails.client
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ require "influxdb/rails/middleware/subscriber"
2
+
3
+ module InfluxDB
4
+ module Rails
5
+ module Middleware
6
+ class ActionMailerSubscriber < Subscriber # :nodoc:
7
+ private
8
+
9
+ def values
10
+ { value: 1 }
11
+ end
12
+
13
+ def tags
14
+ {
15
+ hook: "deliver",
16
+ mailer: payload[:mailer],
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,67 @@
1
+ require "influxdb/rails/middleware/subscriber"
2
+
3
+ module InfluxDB
4
+ module Rails
5
+ module Middleware
6
+ class ActiveJobSubscriber < Subscriber # :nodoc:
7
+ private
8
+
9
+ JOB_STATE = {
10
+ "enqueue" => "queued",
11
+ "perform_start" => "running",
12
+ "perform" => "succeeded",
13
+ }.freeze
14
+ private_constant :JOB_STATE
15
+
16
+ def values
17
+ {
18
+ value: value,
19
+ }
20
+ end
21
+
22
+ def tags
23
+ {
24
+ hook: short_hook_name,
25
+ state: job_state,
26
+ job: job.class.name,
27
+ queue: job.queue_name,
28
+ }
29
+ end
30
+
31
+ def job_state
32
+ return "failed" if failed?
33
+
34
+ JOB_STATE[short_hook_name]
35
+ end
36
+
37
+ def measure_performance?
38
+ short_hook_name == "perform"
39
+ end
40
+
41
+ def short_hook_name
42
+ @short_hook_name ||= fetch_short_hook_name
43
+ end
44
+
45
+ def fetch_short_hook_name
46
+ return "enqueue" if hook_name.include?("enqueue")
47
+
48
+ "perform"
49
+ end
50
+
51
+ def job
52
+ @job ||= payload[:job]
53
+ end
54
+
55
+ def value
56
+ return duration if measure_performance?
57
+
58
+ 1
59
+ end
60
+
61
+ def failed?
62
+ payload[:aborted]
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ require "influxdb/rails/middleware/subscriber"
2
+ require "influxdb/rails/sql/query"
3
+
4
+ module InfluxDB
5
+ module Rails
6
+ module Middleware
7
+ class ActiveRecordSubscriber < Subscriber # :nodoc:
8
+ private
9
+
10
+ def values
11
+ {
12
+ value: duration,
13
+ record_count: payload[:record_count],
14
+ }
15
+ end
16
+
17
+ def tags
18
+ {
19
+ hook: "instantiation",
20
+ class_name: payload[:class_name],
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ require "influxdb/rails/middleware/subscriber"
2
+
3
+ module InfluxDB
4
+ module Rails
5
+ module Middleware
6
+ class BlockInstrumentationSubscriber < Subscriber
7
+ private
8
+
9
+ def values
10
+ {
11
+ value: duration,
12
+ }.merge(payload[:values].to_h)
13
+ end
14
+
15
+ def tags
16
+ {
17
+ hook: "block_instrumentation",
18
+ name: payload[:name],
19
+ }.merge(payload[:tags].to_h)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,24 +1,30 @@
1
- require "influxdb/rails/middleware/simple_subscriber"
1
+ require "influxdb/rails/middleware/subscriber"
2
2
 
3
3
  module InfluxDB
4
4
  module Rails
5
5
  module Middleware
6
- class RenderSubscriber < SimpleSubscriber # :nodoc:
6
+ class RenderSubscriber < Subscriber # :nodoc:
7
7
  private
8
8
 
9
- def values(started, finished, payload)
10
- super(started, finished, payload).merge(
9
+ def values
10
+ {
11
+ value: duration,
11
12
  count: payload[:count],
12
- cache_hits: payload[:cache_hits]
13
- ).reject { |_, value| value.nil? }
13
+ cache_hits: payload[:cache_hits],
14
+ }
14
15
  end
15
16
 
16
- def tags(payload)
17
- tags = {
18
- location: location,
17
+ def tags
18
+ {
19
+ hook: short_hook_name,
19
20
  filename: payload[:identifier],
20
21
  }
21
- super(tags)
22
+ end
23
+
24
+ def short_hook_name
25
+ return "render_template" if hook_name.include?("render_template")
26
+ return "render_partial" if hook_name.include?("render_partial")
27
+ return "render_collection" if hook_name.include?("render_collection")
22
28
  end
23
29
  end
24
30
  end
@@ -4,46 +4,39 @@ module InfluxDB
4
4
  module Rails
5
5
  module Middleware
6
6
  class RequestSubscriber < Subscriber # :nodoc:
7
- def call(_name, start, finish, _id, payload) # rubocop:disable Metrics/MethodLength
8
- return unless enabled?
9
-
10
- ts = InfluxDB.convert_timestamp(finish.utc, configuration.time_precision)
11
- tags = tags(payload)
12
- begin
13
- series(payload, start, finish).each do |series_name, value|
14
- InfluxDB::Rails.client.write_point \
15
- series_name,
16
- values: { value: value },
17
- tags: tags,
18
- timestamp: ts
19
- end
20
- rescue StandardError => e
21
- log :error, "[InfluxDB::Rails] Unable to write points: #{e.message}"
22
- ensure
23
- InfluxDB::Rails.current.reset
24
- end
7
+ def write
8
+ super
9
+ ensure
10
+ InfluxDB::Rails.current.reset
25
11
  end
26
12
 
27
13
  private
28
14
 
29
- def series(payload, start, finish)
15
+ def tags
30
16
  {
31
- configuration.series_name_for_controller_runtimes => ((finish - start) * 1000).ceil,
32
- configuration.series_name_for_view_runtimes => (payload[:view_runtime] || 0).ceil,
33
- configuration.series_name_for_db_runtimes => (payload[:db_runtime] || 0).ceil,
34
- }
35
- end
36
-
37
- def tags(payload)
38
- tags = {
39
17
  method: "#{payload[:controller]}##{payload[:action]}",
18
+ hook: "process_action",
40
19
  status: payload[:status],
41
20
  format: payload[:format],
42
21
  http_method: payload[:method],
43
- server: Socket.gethostname,
44
- app_name: configuration.application_name,
22
+ exception: payload[:exception]&.first,
23
+ }
24
+ end
25
+
26
+ def values
27
+ {
28
+ controller: duration,
29
+ view: (payload[:view_runtime] || 0).ceil,
30
+ db: (payload[:db_runtime] || 0).ceil,
31
+ started: started,
45
32
  }
46
- super(tags)
33
+ end
34
+
35
+ def started
36
+ InfluxDB.convert_timestamp(
37
+ start.utc,
38
+ configuration.client.time_precision
39
+ )
47
40
  end
48
41
  end
49
42
  end
@@ -1,31 +1,35 @@
1
- require "influxdb/rails/middleware/simple_subscriber"
1
+ require "influxdb/rails/middleware/subscriber"
2
2
  require "influxdb/rails/sql/query"
3
3
 
4
4
  module InfluxDB
5
5
  module Rails
6
6
  module Middleware
7
- class SqlSubscriber < SimpleSubscriber # :nodoc:
8
- def call(_name, started, finished, _unique_id, payload)
9
- return unless InfluxDB::Rails::Sql::Query.new(payload).track?
10
-
11
- super
12
- end
13
-
7
+ class SqlSubscriber < Subscriber # :nodoc:
14
8
  private
15
9
 
16
- def values(started, finished, payload)
17
- super.merge(sql: InfluxDB::Rails::Sql::Normalizer.new(payload[:sql]).perform)
10
+ def values
11
+ {
12
+ value: duration,
13
+ sql: InfluxDB::Rails::Sql::Normalizer.new(payload[:sql]).perform,
14
+ }
18
15
  end
19
16
 
20
- def tags(payload)
21
- query = InfluxDB::Rails::Sql::Query.new(payload)
22
- tags = {
23
- location: location,
17
+ def tags
18
+ {
19
+ hook: "sql",
24
20
  operation: query.operation,
25
21
  class_name: query.class_name,
26
22
  name: query.name,
23
+ location: :raw,
27
24
  }
28
- super(tags)
25
+ end
26
+
27
+ def disabled?
28
+ super || !query.track?
29
+ end
30
+
31
+ def query
32
+ @query ||= InfluxDB::Rails::Sql::Query.new(payload)
29
33
  end
30
34
  end
31
35
  end