influxdb-rails 1.0.0.beta1 → 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7b5a411b14d5a465a1a4c503498d8c642de1c818213dfe3e437a1177eefa5d1
|
4
|
+
data.tar.gz: f50dc54acb96ac4e9b758aa5be109ffd40a1396b4e43844800fc670496c1d76c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 123a265d9418ff25a10b469cb798e9ed004af8a679fde861c40f81c5f96a20aea192576d10dfed877293afa6c59412cccb40d0b7fd14e52461aaa76c6712c092
|
7
|
+
data.tar.gz: 6189e83dfce1d8812c0ce8553f3095ee0be21608f71db0375edc1e6aab4cfaf646675d481ed53144056437b853df71a9e9085009fea936384a167bdac41d0433
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,14 @@
|
|
3
3
|
For the full commit log, [see here](https://github.com/influxdata/influxdb-rails/commits/master).
|
4
4
|
|
5
5
|
|
6
|
+
## v1.0.0.beta2, released 2018-12-07
|
7
|
+
|
8
|
+
- Added `tags_middleware` config option (#47, @ @Kukunin)
|
9
|
+
- Removed path tag from metrics (introduced with #50), because it
|
10
|
+
potentially produces "exceed tag value limit" (#54, @ChrisBr)
|
11
|
+
- Added render instrumentation (#53, @ChrisBr)
|
12
|
+
- Added SQL instrumentation (#55, @ChrisBr)
|
13
|
+
|
6
14
|
## v1.0.0.beta1, released 2018-11-22
|
7
15
|
|
8
16
|
- Added app name to the measurement's tag sets (#44, @stefanhorning)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -11,9 +11,10 @@
|
|
11
11
|
Automatically instrument your Ruby on Rails applications and write the
|
12
12
|
metrics directly into [InfluxDB](http://influxdb.org/).
|
13
13
|
|
14
|
-
This gem is designed for Rails 4.
|
14
|
+
This gem is designed for Rails 4.2+, Ruby 2.3+ and InfluxDB 0.9+.
|
15
15
|
|
16
|
-
|
16
|
+
|
17
|
+
## Installation
|
17
18
|
|
18
19
|
```
|
19
20
|
$ [sudo] gem install influxdb-rails
|
@@ -21,6 +22,7 @@ $ [sudo] gem install influxdb-rails
|
|
21
22
|
|
22
23
|
Or add it to your `Gemfile`, etc.
|
23
24
|
|
25
|
+
|
24
26
|
## Usage
|
25
27
|
|
26
28
|
To get things set up, just create an initializer:
|
@@ -48,9 +50,15 @@ InfluxDB::Rails.configure do |config|
|
|
48
50
|
# config.max_delay = 300
|
49
51
|
# config.time_precision = 'ms'
|
50
52
|
|
53
|
+
# config.tags_middleware = ->(tags) { tags }
|
54
|
+
|
51
55
|
# config.series_name_for_controller_runtimes = "rails.controller"
|
52
56
|
# config.series_name_for_view_runtimes = "rails.view"
|
53
57
|
# config.series_name_for_db_runtimes = "rails.db"
|
58
|
+
# config.series_name_for_render_template = "rails.render_template"
|
59
|
+
# config.series_name_for_render_partial = "rails.render_partial"
|
60
|
+
# config.series_name_for_render_collection = "rails.render_collection"
|
61
|
+
# config.series_name_for_sql = nil
|
54
62
|
# config.series_name_for_exceptions = "rails.exceptions"
|
55
63
|
# config.series_name_for_instrumentation = "instrumentation"
|
56
64
|
|
@@ -64,8 +72,21 @@ To see all default values, take a look into `InfluxDB::Rails::Configuration::DEF
|
|
64
72
|
defined in `lib/influxdb/rails/configuration.rb`
|
65
73
|
|
66
74
|
Out of the box, you'll automatically get reporting of your controller,
|
67
|
-
view, and db runtimes
|
68
|
-
|
75
|
+
view, and db runtimes and rendering of template, partial and collection for each request.
|
76
|
+
Reporting of SQL queries is disabled by default because it is still in experimental mode
|
77
|
+
and currently requires String parsing which might cause performance issues on query
|
78
|
+
intensive applications. You can enable it by setting the `series_name_for_sql`
|
79
|
+
configuration.
|
80
|
+
|
81
|
+
It is possible to disable the rendering series by setting the series_name to nil.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# config.series_name_for_render_template = nil
|
85
|
+
# config.series_name_for_render_partial = nil
|
86
|
+
# config.series_name_for_render_collection = nil
|
87
|
+
```
|
88
|
+
|
89
|
+
You can also call through to the underlying `InfluxDB::Client` object to write arbitrary data like this:
|
69
90
|
|
70
91
|
``` ruby
|
71
92
|
InfluxDB::Rails.client.write_point "events",
|
@@ -76,6 +97,53 @@ InfluxDB::Rails.client.write_point "events",
|
|
76
97
|
Additional documentation for `InfluxDB::Client` lives in the
|
77
98
|
[influxdb-ruby](http://github.com/influxdata/influxdb-ruby) repo.
|
78
99
|
|
100
|
+
|
101
|
+
### Tags
|
102
|
+
|
103
|
+
You can modify the tags sent to InfluxDB by defining a middleware, which
|
104
|
+
receives the current tag set (`Hash` with `Symbol` keys and `String`
|
105
|
+
values) as argument and returns a hash in the same form. The middleware
|
106
|
+
can be any object, as long it responds to `#call` (like a `Proc`):
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
InfluxDB::Rails.configure do |config|
|
110
|
+
config.tags_middleware = lambda do |tags|
|
111
|
+
tags.merge(env: Rails.env)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
By default, the following tags are sent for *non-exception series*
|
117
|
+
(`rails.controller`, `rails.view`, `rails.db` and `instrumentation`):
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
{
|
121
|
+
method: "#{payload[:controller]}##{payload[:action]}",
|
122
|
+
server: Socket.gethostname,
|
123
|
+
app_name: configuration.application_name,
|
124
|
+
}
|
125
|
+
```
|
126
|
+
|
127
|
+
and for the exceptions (series name `rails.exceptions`):
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
{
|
131
|
+
application_name: InfluxDB::Rails.configuration.application_name,
|
132
|
+
application_root: InfluxDB::Rails.configuration.application_root,
|
133
|
+
framework: InfluxDB::Rails.configuration.framework,
|
134
|
+
framework_version: InfluxDB::Rails.configuration.framework_version,
|
135
|
+
language: "Ruby",
|
136
|
+
language_version: "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}",
|
137
|
+
custom_data: @custom_data,
|
138
|
+
class: @exception.class.to_s,
|
139
|
+
method: "#{@controller}##{@action}",
|
140
|
+
filename: File.basename(@backtrace.lines.first.try(:file)),
|
141
|
+
server: Socket.gethostname,
|
142
|
+
status: "open",
|
143
|
+
}
|
144
|
+
```
|
145
|
+
|
146
|
+
|
79
147
|
## Frequently Asked Questions
|
80
148
|
|
81
149
|
|
@@ -157,6 +225,7 @@ bundle
|
|
157
225
|
bundle exec rake
|
158
226
|
```
|
159
227
|
|
228
|
+
|
160
229
|
## Contributing
|
161
230
|
|
162
231
|
- Fork this repository on GitHub.
|
@@ -165,11 +234,8 @@ bundle exec rake
|
|
165
234
|
- Add an entry in the `CHANGELOG.md` in the "unreleased" section on top.
|
166
235
|
- Run the tests:
|
167
236
|
- Either run them manually:
|
168
|
-
```
|
169
|
-
|
170
|
-
BUNDLE_GEMFILE=$gemfile bundle install --quiet; \
|
171
|
-
BUNDLE_GEMFILE=$gemfile bundle exec rspec; \
|
172
|
-
done
|
237
|
+
```console
|
238
|
+
$ rake test:all
|
173
239
|
```
|
174
240
|
- or wait for [Travis][travis-pr] to pick up your changes, *after*
|
175
241
|
you made a pull request.
|
data/Rakefile
CHANGED
@@ -2,28 +2,27 @@ require "bundler/gem_tasks"
|
|
2
2
|
require "rubocop/rake_task"
|
3
3
|
RuboCop::RakeTask.new
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
file_pattern = targeted_files.empty? ? "spec/**/*_spec.rb" : targeted_files
|
5
|
+
targeted_files = ARGV.drop(1)
|
6
|
+
file_pattern = targeted_files.empty? ? "spec/**/*_spec.rb" : targeted_files
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
require "rspec/core"
|
9
|
+
require "rspec/core/rake_task"
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
12
|
+
t.pattern = FileList[file_pattern]
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
rescue LoadError
|
21
|
-
require "spec/rake/spectask"
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.color = true
|
17
|
+
config.formatter = :documentation
|
18
|
+
end
|
22
19
|
|
23
|
-
|
20
|
+
task default: %i[spec rubocop]
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
task "test:all" => :default do
|
23
|
+
Dir.glob("gemfiles/Gemfile.rails-*.x") do |gemfile|
|
24
|
+
puts RSpec::Core::Formatters::ConsoleCodes.wrap(gemfile, :cyan)
|
25
|
+
sh({ "BUNDLE_GEMFILE" => gemfile }, "bundle", "install", "--quiet", "--retry=2", "--jobs=2")
|
26
|
+
sh({ "BUNDLE_GEMFILE" => gemfile }, "bundle", "exec", "rspec")
|
28
27
|
end
|
29
28
|
end
|
data/influxdb-rails.gemspec
CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.required_ruby_version = ">= 2.3.0"
|
21
21
|
|
22
|
-
spec.add_runtime_dependency "influxdb", "~> 0.
|
23
|
-
spec.add_runtime_dependency "railties", "
|
22
|
+
spec.add_runtime_dependency "influxdb", "~> 0.6", ">= 0.6.4"
|
23
|
+
spec.add_runtime_dependency "railties", ">= 4.2"
|
24
24
|
|
25
|
+
spec.add_development_dependency "activerecord"
|
25
26
|
spec.add_development_dependency "bundler", ">= 1.0.0"
|
26
27
|
spec.add_development_dependency "fakeweb"
|
27
28
|
spec.add_development_dependency "rake"
|
@@ -29,5 +30,6 @@ Gem::Specification.new do |spec|
|
|
29
30
|
spec.add_development_dependency "rspec"
|
30
31
|
spec.add_development_dependency "rspec-rails", ">= 3.0.0"
|
31
32
|
spec.add_development_dependency "rubocop", "~> 0.60.0"
|
33
|
+
spec.add_development_dependency "sqlite3"
|
32
34
|
spec.add_development_dependency "tzinfo"
|
33
35
|
end
|
@@ -21,7 +21,12 @@ module InfluxDB
|
|
21
21
|
attr_accessor :series_name_for_db_runtimes
|
22
22
|
attr_accessor :series_name_for_exceptions
|
23
23
|
attr_accessor :series_name_for_instrumentation
|
24
|
+
attr_accessor :series_name_for_render_template
|
25
|
+
attr_accessor :series_name_for_render_partial
|
26
|
+
attr_accessor :series_name_for_render_collection
|
27
|
+
attr_accessor :series_name_for_sql
|
24
28
|
|
29
|
+
attr_accessor :tags_middleware
|
25
30
|
attr_accessor :rails_app_name
|
26
31
|
|
27
32
|
attr_accessor :application_name
|
@@ -65,7 +70,12 @@ module InfluxDB
|
|
65
70
|
series_name_for_db_runtimes: "rails.db".freeze,
|
66
71
|
series_name_for_exceptions: "rails.exceptions".freeze,
|
67
72
|
series_name_for_instrumentation: "instrumentation".freeze,
|
73
|
+
series_name_for_render_template: "rails.render_template".freeze,
|
74
|
+
series_name_for_render_partial: "rails.render_partial".freeze,
|
75
|
+
series_name_for_render_collection: "rails.render_collection".freeze,
|
76
|
+
series_name_for_sql: nil,
|
68
77
|
|
78
|
+
tags_middleware: ->(tags) { tags },
|
69
79
|
rails_app_name: nil,
|
70
80
|
|
71
81
|
ignored_exceptions: %w[
|
@@ -124,7 +134,12 @@ module InfluxDB
|
|
124
134
|
@series_name_for_db_runtimes = DEFAULTS[:series_name_for_db_runtimes]
|
125
135
|
@series_name_for_exceptions = DEFAULTS[:series_name_for_exceptions]
|
126
136
|
@series_name_for_instrumentation = DEFAULTS[:series_name_for_instrumentation]
|
137
|
+
@series_name_for_render_template = DEFAULTS[:series_name_for_render_template]
|
138
|
+
@series_name_for_render_partial = DEFAULTS[:series_name_for_render_partial]
|
139
|
+
@series_name_for_render_collection = DEFAULTS[:series_name_for_render_collection]
|
140
|
+
@series_name_for_sql = DEFAULTS[:series_name_for_sql]
|
127
141
|
|
142
|
+
@tags_middleware = DEFAULTS[:tags_middleware]
|
128
143
|
@rails_app_name = DEFAULTS[:rails_app_name]
|
129
144
|
|
130
145
|
@ignored_exceptions = DEFAULTS[:ignored_exceptions].dup
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module InfluxDB
|
2
2
|
module Rails
|
3
3
|
module Instrumentation # rubocop:disable Style/Documentation
|
4
|
-
def
|
4
|
+
def benchmark_for_instrumentation # rubocop:disable Metrics/MethodLength
|
5
5
|
start = Time.now
|
6
6
|
yield
|
7
7
|
|
@@ -13,10 +13,10 @@ module InfluxDB
|
|
13
13
|
values: {
|
14
14
|
value: ((Time.now - start) * 1000).ceil,
|
15
15
|
},
|
16
|
-
tags:
|
16
|
+
tags: configuration.tags_middleware.call(
|
17
17
|
method: "#{controller_name}##{action_name}",
|
18
|
-
server: Socket.gethostname
|
19
|
-
|
18
|
+
server: Socket.gethostname
|
19
|
+
)
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.included(base)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "influxdb/rails/middleware/simple_subscriber"
|
2
|
+
|
3
|
+
module InfluxDB
|
4
|
+
module Rails
|
5
|
+
module Middleware
|
6
|
+
class RenderSubscriber < SimpleSubscriber # :nodoc:
|
7
|
+
private
|
8
|
+
|
9
|
+
def tags(payload)
|
10
|
+
{
|
11
|
+
location: location,
|
12
|
+
filename: payload[:identifier],
|
13
|
+
count: payload[:count],
|
14
|
+
cache_hits: payload[:cache_hits],
|
15
|
+
}.reject { |_, value| value.blank? }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "influxdb/rails/middleware/subscriber"
|
2
|
+
|
3
|
+
module InfluxDB
|
4
|
+
module Rails
|
5
|
+
module Middleware
|
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
|
+
Thread.current[:_influxdb_rails_controller] = nil
|
24
|
+
Thread.current[:_influxdb_rails_action] = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def series(payload, start, finish)
|
31
|
+
{
|
32
|
+
configuration.series_name_for_controller_runtimes => ((finish - start) * 1000).ceil,
|
33
|
+
configuration.series_name_for_view_runtimes => (payload[:view_runtime] || 0).ceil,
|
34
|
+
configuration.series_name_for_db_runtimes => (payload[:db_runtime] || 0).ceil,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def tags(payload)
|
39
|
+
configuration.tags_middleware.call({
|
40
|
+
method: "#{payload[:controller]}##{payload[:action]}",
|
41
|
+
status: payload[:status],
|
42
|
+
format: payload[:format],
|
43
|
+
http_method: payload[:method],
|
44
|
+
server: Socket.gethostname,
|
45
|
+
app_name: configuration.application_name,
|
46
|
+
}.reject { |_, value| value.nil? })
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "influxdb/rails/middleware/subscriber"
|
2
|
+
|
3
|
+
module InfluxDB
|
4
|
+
module Rails
|
5
|
+
module Middleware
|
6
|
+
# Subscriber acts as base class for different *Subscriber classes,
|
7
|
+
# which are intended as ActiveSupport::Notifications.subscribe
|
8
|
+
# consumers.
|
9
|
+
class SimpleSubscriber < Subscriber
|
10
|
+
attr_reader :series_name
|
11
|
+
|
12
|
+
def initialize(configuration, series_name)
|
13
|
+
super(configuration)
|
14
|
+
@series_name = series_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(_name, started, finished, _unique_id, payload)
|
18
|
+
return unless enabled?
|
19
|
+
|
20
|
+
begin
|
21
|
+
InfluxDB::Rails.client.write_point series_name,
|
22
|
+
values: values(started, finished, payload),
|
23
|
+
tags: tags(payload),
|
24
|
+
timestamp: timestamp(finished.utc)
|
25
|
+
rescue StandardError => e
|
26
|
+
log :error, "[InfluxDB::Rails] Unable to write points: #{e.message}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def values(started, finished, _payload)
|
33
|
+
{ value: ((finished - started) * 1000).ceil }
|
34
|
+
end
|
35
|
+
|
36
|
+
def timestamp(finished)
|
37
|
+
InfluxDB.convert_timestamp(finished.utc, configuration.time_precision)
|
38
|
+
end
|
39
|
+
|
40
|
+
def enabled?
|
41
|
+
super && series_name.present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "influxdb/rails/middleware/simple_subscriber"
|
2
|
+
require "influxdb/rails/sql/query"
|
3
|
+
|
4
|
+
module InfluxDB
|
5
|
+
module Rails
|
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
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def values(started, finished, payload)
|
17
|
+
super.merge(sql: InfluxDB::Rails::Sql::Normalizer.new(payload[:sql]).perform)
|
18
|
+
end
|
19
|
+
|
20
|
+
def tags(payload)
|
21
|
+
query = InfluxDB::Rails::Sql::Query.new(payload)
|
22
|
+
{
|
23
|
+
location: location,
|
24
|
+
operation: query.operation,
|
25
|
+
class_name: query.class_name,
|
26
|
+
name: query.name,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "influxdb/rails/logger"
|
2
|
+
|
3
|
+
module InfluxDB
|
4
|
+
module Rails
|
5
|
+
module Middleware
|
6
|
+
# Subscriber acts as base class for different *Subscriber classes,
|
7
|
+
# which are intended as ActiveSupport::Notifications.subscribe
|
8
|
+
# consumers.
|
9
|
+
class Subscriber
|
10
|
+
include InfluxDB::Rails::Logger
|
11
|
+
|
12
|
+
attr_reader :configuration
|
13
|
+
|
14
|
+
def initialize(configuration)
|
15
|
+
@configuration = configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(*)
|
19
|
+
raise NotImplementedError, "must be implemented in subclass"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def enabled?
|
25
|
+
configuration.instrumentation_enabled? &&
|
26
|
+
!configuration.ignore_current_environment?
|
27
|
+
end
|
28
|
+
|
29
|
+
def location
|
30
|
+
[
|
31
|
+
Thread.current[:_influxdb_rails_controller],
|
32
|
+
Thread.current[:_influxdb_rails_action],
|
33
|
+
].reject(&:blank?).join("#")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -8,7 +8,7 @@ module InfluxDB
|
|
8
8
|
app.config.middleware.insert 0, InfluxDB::Rails::Rack
|
9
9
|
end
|
10
10
|
|
11
|
-
config.after_initialize do
|
11
|
+
config.after_initialize do # rubocop:disable Metrics/BlockLength
|
12
12
|
InfluxDB::Rails.configure(true, &:load_rails_defaults)
|
13
13
|
|
14
14
|
ActiveSupport.on_load(:action_controller) do
|
@@ -22,19 +22,27 @@ module InfluxDB
|
|
22
22
|
::ActionDispatch::DebugExceptions.prepend InfluxDB::Rails::Middleware::HijackRenderException
|
23
23
|
|
24
24
|
if defined?(ActiveSupport::Notifications)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
if c.instrumentation_enabled? && !c.ignore_current_environment?
|
29
|
-
begin
|
30
|
-
InfluxDB::Rails.handle_action_controller_metrics(name, start, finish, id, payload)
|
31
|
-
rescue StandardError => e
|
32
|
-
c.logger.error "[InfluxDB::Rails] Failed writing points to InfluxDB: #{e.message}"
|
33
|
-
end
|
34
|
-
end
|
25
|
+
cache = lambda do |_, _, _, _, payload|
|
26
|
+
Thread.current[:_influxdb_rails_controller] = payload[:controller]
|
27
|
+
Thread.current[:_influxdb_rails_action] = payload[:action]
|
35
28
|
end
|
29
|
+
ActiveSupport::Notifications.subscribe "start_processing.action_controller", &cache
|
36
30
|
|
37
|
-
|
31
|
+
c = InfluxDB::Rails.configuration
|
32
|
+
requests = Middleware::RequestSubscriber.new(c)
|
33
|
+
ActiveSupport::Notifications.subscribe "process_action.action_controller", requests
|
34
|
+
|
35
|
+
templates = Middleware::RenderSubscriber.new(c, c.series_name_for_render_template)
|
36
|
+
ActiveSupport::Notifications.subscribe "render_template.action_view", templates
|
37
|
+
|
38
|
+
partials = Middleware::RenderSubscriber.new(c, c.series_name_for_render_partial)
|
39
|
+
ActiveSupport::Notifications.subscribe "render_partial.action_view", partials
|
40
|
+
|
41
|
+
collections = Middleware::RenderSubscriber.new(c, c.series_name_for_render_collection)
|
42
|
+
ActiveSupport::Notifications.subscribe "render_collection.action_view", collections
|
43
|
+
|
44
|
+
sql = Middleware::SqlSubscriber.new(c, c.series_name_for_sql)
|
45
|
+
ActiveSupport::Notifications.subscribe "sql.active_record", sql
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module InfluxDB
|
2
|
+
module Rails
|
3
|
+
module Sql
|
4
|
+
class Normalizer # :nodoc:
|
5
|
+
def initialize(query)
|
6
|
+
@query = query.dup
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
query.squish!
|
11
|
+
query.gsub!(/(\s(=|>|<|>=|<=|<>|!=)\s)('[^']+'|[\$\+\-\w\.]+)/, '\1xxx')
|
12
|
+
query.gsub!(/(\sIN\s)\([^\(\)]+\)/i, '\1(xxx)')
|
13
|
+
regex = /(\sBETWEEN\s)('[^']+'|[\+\-\w\.]+)(\sAND\s)('[^']+'|[\+\-\w\.]+)/i
|
14
|
+
query.gsub!(regex, '\1xxx\3xxx')
|
15
|
+
query.gsub!(/(\sVALUES\s)\(.+\)/i, '\1(xxx)')
|
16
|
+
query.gsub!(/(\s(LIKE|ILIKE|SIMILAR TO|NOT SIMILAR TO)\s)('[^']+')/i, '\1xxx')
|
17
|
+
query.gsub!(/(\s(LIMIT|OFFSET)\s)(\d+)/i, '\1xxx')
|
18
|
+
query
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :query
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "influxdb/rails/sql/normalizer"
|
2
|
+
|
3
|
+
module InfluxDB
|
4
|
+
module Rails
|
5
|
+
module Sql
|
6
|
+
class Query # :nodoc:
|
7
|
+
attr_reader :query, :name
|
8
|
+
|
9
|
+
TRACKED_SQL_COMMANDS = %w[SELECT INSERT UPDATE DELETE].freeze
|
10
|
+
|
11
|
+
def initialize(payload)
|
12
|
+
@query = payload[:sql].to_s.dup
|
13
|
+
@name = payload[:name].to_s.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
def operation
|
17
|
+
query.split.first.upcase
|
18
|
+
end
|
19
|
+
|
20
|
+
def class_name
|
21
|
+
name.split.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def track?
|
25
|
+
@track ||= query.start_with?(*TRACKED_SQL_COMMANDS)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|