elastics 0.3.0 → 0.4.0
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/.travis.yml +2 -0
- data/Gemfile +6 -0
- data/README.md +64 -6
- data/lib/elastics.rb +7 -15
- data/lib/elastics/active_record.rb +15 -18
- data/lib/elastics/active_record/helper_methods.rb +5 -44
- data/lib/elastics/active_record/model_schema.rb +3 -26
- data/lib/elastics/client.rb +4 -4
- data/lib/elastics/client/cluster.rb +47 -32
- data/lib/elastics/instrumentation.rb +38 -0
- data/lib/elastics/instrumentation/active_support.rb +70 -0
- data/lib/elastics/model.rb +18 -0
- data/lib/elastics/model/connection.rb +19 -0
- data/lib/elastics/model/helper_methods.rb +67 -0
- data/lib/elastics/model/schema.rb +32 -0
- data/lib/elastics/model/skipping.rb +42 -0
- data/lib/elastics/model/tracking.rb +29 -0
- data/lib/elastics/railtie.rb +1 -1
- data/lib/elastics/tasks/config.rb +1 -1
- data/lib/elastics/tasks/migrations.rb +1 -1
- data/lib/elastics/version.rb +1 -1
- data/lib/elastics/version_manager.rb +1 -1
- data/spec/lib/elastics/auto_refresh_spec.rb +2 -2
- data/spec/lib/elastics/client/cluster_spec.rb +59 -0
- data/spec/lib/elastics/instrumentation_spec.rb +71 -0
- data/spec/lib/elastics/model/schema_spec.rb +24 -0
- data/spec/spec_helper.rb +1 -0
- metadata +15 -3
- data/lib/elastics/active_record/instrumentation.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca7add0bf62591b992bdcbb03cf08461cf208204
|
4
|
+
data.tar.gz: 5f2b845c2cf49a89e6f4414dfad2dd505ed56784
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da3920ea1f157297b6c3e5fea2b7ead3620493fb887ee34bd6191b8428ab74763fb324246be193fbd5e2fc32268f7f61331680a02f087d6ce3c619d9d7da1820
|
7
|
+
data.tar.gz: 262e2e0efec270bed5eac991e706298220bf67f5024efd6ae99782d94efb86380c95bf40bcc9dc2779e423205d6c00441a9b72968921894d3bd5fb3869034cab
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -32,8 +32,6 @@ client = Elastics::Client.new(options)
|
|
32
32
|
# :host - hostname with port or array with hosts (default 127.0.0.1:9200)
|
33
33
|
# :index - (default index)
|
34
34
|
# :type - (default type)
|
35
|
-
# :connect_timeout - timeout to mark the host as dead in cluster-mode (default 10)
|
36
|
-
# :resurrect_timeout - timeout to mark dead host as alive in cluster-mode (default 10)
|
37
35
|
|
38
36
|
# basic request
|
39
37
|
client.request(params)
|
@@ -70,7 +68,21 @@ client.bulk(params) do |bulk|
|
|
70
68
|
end
|
71
69
|
```
|
72
70
|
|
73
|
-
|
71
|
+
### Models
|
72
|
+
Most of ActiveRecord integration functionality is available for plain ruby.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class User
|
76
|
+
include Elastics::Model
|
77
|
+
|
78
|
+
# set connection config, check 'configure section' for available options
|
79
|
+
self.elastics_config = {host: 'hostname:port'}
|
80
|
+
# set index base and version manager will manage aliases
|
81
|
+
self.elastics_index_base = 'user'
|
82
|
+
self.elastics_type_name = 'user'
|
83
|
+
end
|
84
|
+
```
|
85
|
+
Check out available [HelperMethods](https://github.com/printercu/elastics-rb/blob/master/lib/elastics/model/helper_methods.rb).
|
74
86
|
|
75
87
|
### ActiveRecord
|
76
88
|
|
@@ -91,8 +103,13 @@ User.elastics_params # hash with index & type values for the model
|
|
91
103
|
User.request_elastics(params) # performs request merging params with elastics_params
|
92
104
|
User.search_elastics(data)
|
93
105
|
# Returns Elastics::ActiveRecord::SearchResult object with some useful methods
|
106
|
+
|
107
|
+
# Indexing on create/update can be skipped with skip_elastics
|
108
|
+
User.skip_elastics { users.each { |x| x.update_attributes(smth: 'not indexed') } }
|
109
|
+
user.skip_elastics { user.update_attributes(smth: 'not indexed') }
|
94
110
|
```
|
95
|
-
Check out [HelperMethods](https://github.com/printercu/elastics-rb/blob/master/lib/elastics/
|
111
|
+
Check out [Model::HelperMethods](https://github.com/printercu/elastics-rb/blob/master/lib/elastics/model/helper_methods.rb)
|
112
|
+
and [AR::HelperMethods](https://github.com/printercu/elastics-rb/blob/master/lib/elastics/active_record/helper_methods.rb)
|
96
113
|
for more information.
|
97
114
|
|
98
115
|
#### Configure
|
@@ -171,8 +188,7 @@ task :environment do
|
|
171
188
|
end
|
172
189
|
```
|
173
190
|
|
174
|
-
Also you need to install `active_support`
|
175
|
-
`active_support/core_ext/object` to be able to run tasks.
|
191
|
+
Also you need to install `active_support` to be able to run tasks.
|
176
192
|
|
177
193
|
### Auto refresh index
|
178
194
|
Add `Elastics::AutoRefresh.enable!` to your test helper,
|
@@ -189,6 +205,48 @@ Elastics::AutoRefresh.disable! { Model.reindex_elastics }
|
|
189
205
|
Model.refresh_elastics
|
190
206
|
```
|
191
207
|
|
208
|
+
### Instrumentation
|
209
|
+
Instrumentation works out of box in rails. For pure ruby there is only
|
210
|
+
ActiveSupport version (remember to install gem).
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
# Activate instrumentation (no need for rails)
|
214
|
+
Elastics::Instrumentation::ActiveSupport.install
|
215
|
+
|
216
|
+
# Activate body prettifier (off by default)
|
217
|
+
Elastics::Instrumentation.body_prettifier = true
|
218
|
+
# can be
|
219
|
+
# true - JSON.pretty_generate
|
220
|
+
# :ap - awesome_print
|
221
|
+
# :pp - pretty_print
|
222
|
+
# Proc - ->(str) { your_prettifier(str) }
|
223
|
+
```
|
224
|
+
|
225
|
+
### Connecting to cluster
|
226
|
+
When you pass array in `:host` option to initializer, client will work in cluster mode.
|
227
|
+
There are some options for this mode:
|
228
|
+
- `:connect_timeout` - timeout to mark the host as dead in cluster-mode (default 10)
|
229
|
+
- `:resurrect_timeout` - timeout to mark dead host as alive in cluster-mode (default 60)
|
230
|
+
- `:discover` - enable nodes discovering
|
231
|
+
|
232
|
+
In plain ruby you should also install `thread_safe` gem.
|
233
|
+
|
234
|
+
##### Note about nodes discovering
|
235
|
+
Client will perform requests to discover nodes with enabled http module. After
|
236
|
+
discovering hosts will be overwritten with discovered ones.
|
237
|
+
|
238
|
+
`discover: true` will keep you from editing config too frequently,
|
239
|
+
but keep in mind that you should set enough hosts explicitly, so that discover
|
240
|
+
will be able to continue if some of hosts are down.
|
241
|
+
Also this is performed automaticaly only once, when client is initialized.
|
242
|
+
It will not track nodes that go online after client was instantiated. Anyway you
|
243
|
+
still can call `.discover_cluster` whenever you want, or just restart app when
|
244
|
+
you add more nodes.
|
245
|
+
|
246
|
+
### Thread-safety
|
247
|
+
Elastics designed to be thread-safe. It should be ok to have single client instance
|
248
|
+
for the whole application.
|
249
|
+
|
192
250
|
### Use with capistrano
|
193
251
|
Add following lines to your `deploy.rb` and all rake tasks will be available in cap.
|
194
252
|
|
data/lib/elastics.rb
CHANGED
@@ -4,21 +4,13 @@ module Elastics
|
|
4
4
|
|
5
5
|
require 'elastics/client'
|
6
6
|
|
7
|
-
autoload :AutoRefresh,
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
|
13
|
-
|
14
|
-
attr_reader :models
|
15
|
-
|
16
|
-
def reset_models
|
17
|
-
@models = []
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
reset_models
|
7
|
+
autoload :AutoRefresh, 'elastics/auto_refresh'
|
8
|
+
autoload :Instrumentation, 'elastics/instrumentation'
|
9
|
+
autoload :Model, 'elastics/model'
|
10
|
+
autoload :QueryHelper, 'elastics/query_helper'
|
11
|
+
autoload :Result, 'elastics/result'
|
12
|
+
autoload :Tasks, 'elastics/tasks'
|
13
|
+
autoload :VersionManager, 'elastics/version_manager'
|
22
14
|
end
|
23
15
|
|
24
16
|
require 'elastics/railtie' if defined?(Rails)
|
@@ -5,33 +5,21 @@ module Elastics
|
|
5
5
|
autoload :SearchResult
|
6
6
|
autoload :ModelSchema
|
7
7
|
autoload :HelperMethods
|
8
|
-
autoload :Instrumentation
|
9
|
-
autoload :LogSubscriber, 'elastics/active_record/instrumentation'
|
10
8
|
|
11
9
|
class << self
|
12
10
|
def install
|
13
11
|
::ActiveRecord::Base.extend self
|
14
|
-
Instrumentation.install
|
12
|
+
Instrumentation::ActiveSupport.install
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
16
|
+
include Model::Connection
|
17
|
+
|
18
18
|
def elastics_config
|
19
19
|
@elastics_config ||= connection_config[:elastics].try!(:with_indifferent_access) ||
|
20
20
|
raise('No elastics configuration in database.yml')
|
21
21
|
end
|
22
22
|
|
23
|
-
def elastics
|
24
|
-
@elastics ||= Client.new elastics_config.slice(:host, :port)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Don't memoize to GC it after initialization
|
28
|
-
def elastics_version_manager
|
29
|
-
VersionManager.new(elastics, elastics_config.slice(
|
30
|
-
:service_index,
|
31
|
-
:index_prefix,
|
32
|
-
))
|
33
|
-
end
|
34
|
-
|
35
23
|
def indexed_with_elastics(options = {})
|
36
24
|
options = {
|
37
25
|
hooks: [:update, :destroy],
|
@@ -39,13 +27,22 @@ module Elastics
|
|
39
27
|
|
40
28
|
extend ModelSchema
|
41
29
|
include HelperMethods
|
30
|
+
extend Model::Tracking
|
42
31
|
|
43
32
|
self.elastics_index_base = options[:index] if options[:index]
|
44
33
|
self.elastics_type_name = options[:type] if options[:type]
|
45
34
|
|
46
|
-
|
47
|
-
after_commit :index_elastics, on: [:create, :update] if hooks.include?(:update)
|
48
|
-
after_commit :delete_elastics, on: [:destroy] if hooks.include?(:destroy)
|
35
|
+
install_elastics_hooks(options[:hooks])
|
49
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def install_elastics_hooks(hooks)
|
40
|
+
if hooks.include?(:update)
|
41
|
+
after_commit :index_elastics, on: [:create, :update], unless: :skip_elastics?
|
42
|
+
end
|
43
|
+
if hooks.include?(:destroy)
|
44
|
+
after_commit :delete_elastics, on: [:destroy], unless: :skip_elastics?
|
45
|
+
end
|
46
|
+
end
|
50
47
|
end
|
51
48
|
end
|
@@ -3,27 +3,13 @@ module Elastics
|
|
3
3
|
module HelperMethods
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
def self.append_features(base)
|
7
|
+
base.send :include, Model::HelperMethods
|
8
|
+
base.send :include, Model::Skipping
|
9
|
+
super
|
8
10
|
end
|
9
11
|
|
10
12
|
module ClassMethods
|
11
|
-
def elastics_params
|
12
|
-
{
|
13
|
-
index: elastics_index_name,
|
14
|
-
type: elastics_type_name,
|
15
|
-
model: self,
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
def request_elastics(params)
|
20
|
-
elastics.request(elastics_params.merge!(params))
|
21
|
-
end
|
22
|
-
|
23
|
-
def bulk_elastics(params = {}, &block)
|
24
|
-
elastics.bulk(elastics_params.merge!(params), &block)
|
25
|
-
end
|
26
|
-
|
27
13
|
def search_elastics(data = {}, options = {})
|
28
14
|
request = {
|
29
15
|
id: :_search,
|
@@ -46,11 +32,7 @@ module Elastics
|
|
46
32
|
|
47
33
|
def index_all_elastics(*args)
|
48
34
|
find_in_batches(*args) do |batch|
|
49
|
-
|
50
|
-
batch.each do |record|
|
51
|
-
bulk.index record.id, record.to_elastics
|
52
|
-
end
|
53
|
-
end
|
35
|
+
index_batch_elastics(batch)
|
54
36
|
end
|
55
37
|
end
|
56
38
|
|
@@ -71,27 +53,6 @@ module Elastics
|
|
71
53
|
end
|
72
54
|
scope.index_all_elastics(options)
|
73
55
|
end
|
74
|
-
|
75
|
-
def refresh_elastics
|
76
|
-
request_elastics(method: :post, type: nil, id: :_refresh)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def index_elastics
|
81
|
-
self.class.request_elastics(method: :post, id: id, body: to_elastics)
|
82
|
-
end
|
83
|
-
|
84
|
-
def update_elastics(data)
|
85
|
-
self.class.request_elastics(method: :post, id: "#{id}/_update", body: data)
|
86
|
-
end
|
87
|
-
|
88
|
-
def update_elastics_doc(fields)
|
89
|
-
update_elastics(doc: fields)
|
90
|
-
end
|
91
|
-
|
92
|
-
def delete_elastics
|
93
|
-
self.class.request_elastics(method: :delete, id: id)
|
94
|
-
rescue NotFound
|
95
56
|
end
|
96
57
|
end
|
97
58
|
end
|
@@ -1,22 +1,7 @@
|
|
1
1
|
module Elastics
|
2
2
|
module ActiveRecord
|
3
3
|
module ModelSchema
|
4
|
-
|
5
|
-
def track_model(model)
|
6
|
-
Elastics.models << model unless model.abstract_class?
|
7
|
-
end
|
8
|
-
|
9
|
-
def extended(base)
|
10
|
-
track_model(base)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_writer :elastics_index_base, :elastics_type_name
|
15
|
-
|
16
|
-
def elastics_index_name
|
17
|
-
reset_elastics_index_name unless defined?(@elastics_index_name)
|
18
|
-
@elastics_index_name
|
19
|
-
end
|
4
|
+
include Model::Schema
|
20
5
|
|
21
6
|
def elastics_type_name
|
22
7
|
@elastics_type_name ||= model_name.to_s.demodulize.underscore.singularize
|
@@ -28,16 +13,8 @@ module Elastics
|
|
28
13
|
end
|
29
14
|
end
|
30
15
|
|
31
|
-
def
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def elastics_index_base
|
36
|
-
@elastics_index_base || elastics_config[:index] || elastics_type_name
|
37
|
-
end
|
38
|
-
|
39
|
-
def inherited(base)
|
40
|
-
super.tap { ::Elastics::ActiveRecord::ModelSchema.track_model(base) }
|
16
|
+
def track_elastics_model?
|
17
|
+
!abstract_class?
|
41
18
|
end
|
42
19
|
end
|
43
20
|
end
|
data/lib/elastics/client.rb
CHANGED
@@ -14,15 +14,15 @@ module Elastics
|
|
14
14
|
attr_reader :client
|
15
15
|
|
16
16
|
def initialize(defaults = {})
|
17
|
+
@index = defaults[:index]
|
18
|
+
@type = defaults[:type]
|
19
|
+
@client = HTTPClient.new
|
17
20
|
if defaults[:host].is_a?(Array)
|
18
21
|
extend Cluster
|
19
22
|
initialize_cluster(defaults)
|
20
23
|
else
|
21
24
|
@host = defaults[:host] || '127.0.0.1:9200'
|
22
25
|
end
|
23
|
-
@index = defaults[:index]
|
24
|
-
@type = defaults[:type]
|
25
|
-
@client = HTTPClient.new
|
26
26
|
end
|
27
27
|
|
28
28
|
def debug!(dev = STDOUT)
|
@@ -133,7 +133,7 @@ module Elastics
|
|
133
133
|
# You probably don't want to use this method directly.
|
134
134
|
def http_request(method, path, query, body, params = nil, host = @host)
|
135
135
|
uri = "http://#{host}#{path}"
|
136
|
-
|
136
|
+
client.request(method, uri, query, body, HEADERS)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
@@ -7,14 +7,27 @@ module Elastics
|
|
7
7
|
module Cluster
|
8
8
|
class NoAliveHosts < Error; end
|
9
9
|
|
10
|
+
def discover_cluster
|
11
|
+
# `nothing` allows not to fetch all unnecessary data
|
12
|
+
discovered = request(index: '_nodes', type: '_all', id: 'nothing')['nodes'].
|
13
|
+
map { |id, node|
|
14
|
+
match = node['http_address'].match(/inet\[.*?\/([\da-f.:]+)/i)
|
15
|
+
match && match[1]
|
16
|
+
}.compact
|
17
|
+
@cluster_mutex.synchronize do
|
18
|
+
@hosts.clear.concat(discovered - @dead_hosts.keys)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
10
22
|
private
|
11
23
|
def initialize_cluster(defaults)
|
12
24
|
@hosts = ThreadSafe::Array.new defaults[:host]
|
13
25
|
@dead_hosts = ThreadSafe::Hash.new
|
14
26
|
@connect_timeout = defaults[:connect_timeout] || 10
|
15
|
-
@resurrect_timeout = defaults[:resurrect_timeout] ||
|
27
|
+
@resurrect_timeout = defaults[:resurrect_timeout] || 60
|
16
28
|
@current_host_n = 0
|
17
29
|
@cluster_mutex = Mutex.new
|
30
|
+
discover_cluster if defaults[:discover]
|
18
31
|
end
|
19
32
|
|
20
33
|
def http_request(method, path, query, body, params = nil)
|
@@ -27,44 +40,46 @@ module Elastics
|
|
27
40
|
retry
|
28
41
|
end
|
29
42
|
|
30
|
-
|
31
|
-
|
32
|
-
if
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
# Very simple implementation. It may skip some hosts on current cycle
|
44
|
+
# when other is marked as dead. This should not be a problem.
|
45
|
+
# TODO: check Enumerable#cycle for thread-safety and use it if possible
|
46
|
+
def next_cluster_host
|
47
|
+
if @resurrect_at
|
48
|
+
time = Time.now.to_i
|
49
|
+
resurrect_cluster(time) if @resurrect_at <= time
|
50
|
+
end
|
51
|
+
host_n = @current_host_n
|
52
|
+
loop do
|
53
|
+
host = @hosts[host_n]
|
54
|
+
if !host
|
55
|
+
raise NoAliveHosts if host_n == 0
|
56
|
+
host_n = 0
|
57
|
+
else
|
58
|
+
@current_host_n = host_n + 1
|
59
|
+
return host
|
60
|
+
end
|
45
61
|
end
|
46
62
|
end
|
47
|
-
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
def resurrect_cluster(time = Time.now.to_i)
|
65
|
+
@cluster_mutex.synchronize do
|
66
|
+
@dead_hosts.delete_if do |host, resurrect_at|
|
67
|
+
# skip the rest because values are sorted
|
68
|
+
if time < resurrect_at
|
69
|
+
@resurrect_at = resurrect_at
|
70
|
+
break
|
71
|
+
end
|
72
|
+
@hosts << host
|
56
73
|
end
|
57
|
-
@hosts << host
|
58
74
|
end
|
59
75
|
end
|
60
|
-
end
|
61
76
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
77
|
+
def add_dead_host(host, resurrect_at = nil)
|
78
|
+
resurrect_at ||= Time.now.to_i + @resurrect_timeout
|
79
|
+
@hosts.delete(host)
|
80
|
+
@dead_hosts[host] = resurrect_at
|
81
|
+
@resurrect_at ||= resurrect_at
|
82
|
+
end
|
68
83
|
end
|
69
84
|
end
|
70
85
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Instrumentation
|
3
|
+
autoload :ActiveSupport, 'elastics/instrumentation/active_support'
|
4
|
+
|
5
|
+
PRETTIFIERS = {
|
6
|
+
ap: ->(str) { prettify_json(str, &:awesome_inspect) },
|
7
|
+
pp: ->(str) { prettify_json(str, &:pretty_inspect) },
|
8
|
+
true => ->(str) { prettify_json(str, &JSON.method(:pretty_generate)) },
|
9
|
+
}
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def body_prettifier=(value)
|
13
|
+
@body_prettifier = case value
|
14
|
+
when Proc, nil, false then value
|
15
|
+
else PRETTIFIERS[value] or raise 'Invalid prettifier'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def prettify_body(str)
|
20
|
+
if @body_prettifier
|
21
|
+
@body_prettifier.call(str)
|
22
|
+
else
|
23
|
+
str
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def prettify_json(str, &block)
|
28
|
+
data = [JSON.parse(str)] rescue nil
|
29
|
+
data ||= str.split("\n").map { |x| JSON.parse(x) } rescue nil
|
30
|
+
if data
|
31
|
+
data.map(&block).join("\n")
|
32
|
+
else
|
33
|
+
str
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
require 'active_support/log_subscriber'
|
3
|
+
require 'active_support/notifications'
|
4
|
+
|
5
|
+
module Elastics
|
6
|
+
module Instrumentation
|
7
|
+
module ActiveSupport
|
8
|
+
class << self
|
9
|
+
def install
|
10
|
+
if Client.respond_to?(:prepend)
|
11
|
+
Client.prepend self
|
12
|
+
else
|
13
|
+
Client.send :include, Ruby19Fallback
|
14
|
+
end
|
15
|
+
LogSubscriber.attach_to :elastics
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def http_request(*args)
|
20
|
+
::ActiveSupport::Notifications.instrument 'http_request.elastics', args: args do
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# old rubies support
|
26
|
+
module Ruby19Fallback
|
27
|
+
def self.included(base)
|
28
|
+
base.alias_method_chain :http_request, :as_instrumentation
|
29
|
+
end
|
30
|
+
|
31
|
+
def http_request_with_as_instrumentation(*args)
|
32
|
+
::ActiveSupport::Notifications.instrument 'http_request.elastics', args: args do
|
33
|
+
http_request_without_as_instrumentation(*args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class LogSubscriber < ::ActiveSupport::LogSubscriber
|
39
|
+
def http_request(event)
|
40
|
+
return unless logger.debug?
|
41
|
+
|
42
|
+
payload = event.payload[:args]
|
43
|
+
method, path, query, body, params = payload
|
44
|
+
path = '/' if path.blank?
|
45
|
+
path << "?#{query.to_param}" if query.present?
|
46
|
+
model = params[:model]
|
47
|
+
|
48
|
+
name = ""
|
49
|
+
name << "#{model.name} " if model
|
50
|
+
name << "elastics (#{event.duration.round(1)}ms)"
|
51
|
+
request = "#{method.to_s.upcase} #{path}"
|
52
|
+
request << " #{Instrumentation.prettify_body(body)}" if body.present?
|
53
|
+
|
54
|
+
if odd?
|
55
|
+
name = color(name, ::ActiveSupport::LogSubscriber::CYAN, true)
|
56
|
+
request = color(request, nil, true)
|
57
|
+
else
|
58
|
+
name = color(name, ::ActiveSupport::LogSubscriber::MAGENTA, true)
|
59
|
+
end
|
60
|
+
|
61
|
+
debug " #{name} #{request}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def odd?
|
65
|
+
@odd = !@odd
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
autoload :Connection, 'elastics/model/connection'
|
4
|
+
autoload :HelperMethods, 'elastics/model/helper_methods'
|
5
|
+
autoload :Schema, 'elastics/model/schema'
|
6
|
+
autoload :Skipping, 'elastics/model/skipping'
|
7
|
+
|
8
|
+
require 'elastics/model/tracking'
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.extend Connection
|
12
|
+
base.extend Schema
|
13
|
+
base.extend Tracking
|
14
|
+
base.send :include, HelperMethods
|
15
|
+
base.send :include, Skipping
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
module Connection
|
4
|
+
attr_accessor :elastics_config
|
5
|
+
|
6
|
+
def elastics
|
7
|
+
@elastics ||= Client.new elastics_config.slice(:host)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Don't memoize to GC it after initialization
|
11
|
+
def elastics_version_manager
|
12
|
+
VersionManager.new(elastics, elastics_config.slice(
|
13
|
+
:service_index,
|
14
|
+
:index_prefix,
|
15
|
+
))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
module HelperMethods
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
|
8
|
+
# don't override to_elastics method, if it already exists
|
9
|
+
if !instance_methods.include?(:to_elastics) && instance_methods.include?(:as_json)
|
10
|
+
alias_method :to_elastics, :as_json
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def elastics_params
|
17
|
+
{
|
18
|
+
index: elastics_index_name,
|
19
|
+
type: elastics_type_name,
|
20
|
+
model: self,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def request_elastics(params)
|
25
|
+
elastics.request(elastics_params.merge!(params))
|
26
|
+
end
|
27
|
+
|
28
|
+
def bulk_elastics(params = {}, &block)
|
29
|
+
elastics.bulk(elastics_params.merge!(params), &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def refresh_elastics
|
33
|
+
request_elastics(method: :post, type: nil, id: :_refresh)
|
34
|
+
end
|
35
|
+
|
36
|
+
def index_batch_elastics(batch)
|
37
|
+
bulk_elastics do |bulk|
|
38
|
+
batch.each do |record|
|
39
|
+
bulk.index record.id, record.to_elastics
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def reindex_elastics(options = {})
|
45
|
+
raise 'Not implemented'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def index_elastics
|
50
|
+
self.class.request_elastics(method: :post, id: id, body: to_elastics)
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_elastics(data)
|
54
|
+
self.class.request_elastics(method: :post, id: "#{id}/_update", body: data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_elastics_doc(fields)
|
58
|
+
update_elastics(doc: fields)
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_elastics
|
62
|
+
self.class.request_elastics(method: :delete, id: id)
|
63
|
+
rescue NotFound
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
module Schema
|
4
|
+
attr_writer :elastics_index_base, :elastics_type_name
|
5
|
+
|
6
|
+
def elastics_index_name
|
7
|
+
reset_elastics_index_name unless defined?(@elastics_index_name)
|
8
|
+
@elastics_index_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def elastics_type_name
|
12
|
+
@elastics_type_name ||= name.split('::').last.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset_elastics_index_name
|
16
|
+
@elastics_index_name = if superclass.respond_to?(:elastics_index_name)
|
17
|
+
superclass.elastics_index_name
|
18
|
+
else
|
19
|
+
compute_elastics_index_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def compute_elastics_index_name
|
24
|
+
elastics_version_manager.index_name(elastics_index_base)
|
25
|
+
end
|
26
|
+
|
27
|
+
def elastics_index_base
|
28
|
+
@elastics_index_base || elastics_config[:index] || elastics_type_name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
module Skipping
|
4
|
+
class << self
|
5
|
+
def models
|
6
|
+
Thread.current[:elastics_skip_models] ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def included(base)
|
10
|
+
base.extend self
|
11
|
+
base.extend ClassMethods
|
12
|
+
base.send :include, InstanceMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def skip_elastics
|
17
|
+
self.skip_elastics = true
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
self.skip_elastics = false
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def skip_elastics?
|
25
|
+
Skipping.models[self]
|
26
|
+
end
|
27
|
+
|
28
|
+
def skip_elastics=(val)
|
29
|
+
Skipping.models[self] = val
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
attr_writer :skip_elastics
|
35
|
+
|
36
|
+
def skip_elastics?
|
37
|
+
@skip_elastics || self.class.skip_elastics?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Elastics
|
2
|
+
module Model
|
3
|
+
class << self
|
4
|
+
attr_reader :list
|
5
|
+
|
6
|
+
def reset_list
|
7
|
+
@list = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def track(model)
|
11
|
+
if !model.respond_to?(:track_elastics_model?) || model.track_elastics_model?
|
12
|
+
list << model
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
reset_list
|
18
|
+
|
19
|
+
module Tracking
|
20
|
+
def self.extended(base)
|
21
|
+
Model.track(base)
|
22
|
+
end
|
23
|
+
|
24
|
+
def inherited(base)
|
25
|
+
super.tap { Model.track(base) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/elastics/railtie.rb
CHANGED
@@ -41,7 +41,7 @@ module Elastics
|
|
41
41
|
def models_to_reindex(options = {})
|
42
42
|
indices = options[:indices].try!(:map, &:to_s)
|
43
43
|
types = options[:types].try!(:map, &:to_s)
|
44
|
-
models =
|
44
|
+
models = Model.list.select do |model|
|
45
45
|
next if indices && !indices.include?(model.elastics_index_base)
|
46
46
|
next if types && !types.include?(model.elastics_type_name)
|
47
47
|
true
|
data/lib/elastics/version.rb
CHANGED
@@ -21,14 +21,14 @@ describe Elastics::AutoRefresh do
|
|
21
21
|
it 'invokes refresh after each request' do
|
22
22
|
expect(client).to receive(:refresh).exactly(3).times
|
23
23
|
client.post id: 1
|
24
|
-
client.put_mapping type: {fields: {}}
|
24
|
+
client.put_mapping type: :test, body: {fields: {}}
|
25
25
|
client.delete id: 2
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'invokes refresh after each request, not wrapped in .disable! block' do
|
29
29
|
expect(client).to receive(:refresh).exactly(2).times
|
30
30
|
client.post id: 1
|
31
|
-
described_class.disable! { client.put_mapping type: {fields: {}} }
|
31
|
+
described_class.disable! { client.put_mapping type: :test, body: {fields: {}} }
|
32
32
|
client.delete id: 2
|
33
33
|
end
|
34
34
|
end
|
@@ -105,4 +105,63 @@ describe Elastics::Client do
|
|
105
105
|
it { should raise_error(Elastics::Client::Cluster::NoAliveHosts) }
|
106
106
|
end
|
107
107
|
end
|
108
|
+
|
109
|
+
describe '#discover_cluster' do
|
110
|
+
let(:instance) { described_class.new(host: initial_host, discover: true).tap { |x|
|
111
|
+
x.singleton_class.send :attr_reader, :hosts
|
112
|
+
} }
|
113
|
+
|
114
|
+
let(:initial_host) { ['10.0.0.1:9200', '10.0.0.2:9200', '10.0.0.3:9200']}
|
115
|
+
|
116
|
+
let(:successful_response) do
|
117
|
+
{"cluster_name"=>"elasticsearch_max",
|
118
|
+
"nodes"=>
|
119
|
+
{"one"=>{"http_address"=>"inet[/10.0.0.2:9200]"},
|
120
|
+
"other"=>{"http_address"=>"inet[/10.0.0.1:9200]"}}}
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when nodes discover request fails' do
|
124
|
+
before do
|
125
|
+
expect_any_instance_of(described_class).to receive(:request) { raise Elastics::Error }
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'fails on initialization' do
|
129
|
+
expect { instance }.to raise_error(Elastics::Error)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when request is performed on first node' do
|
134
|
+
before do
|
135
|
+
expect_any_instance_of(described_class).to receive(:request) { successful_response }
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'overwrites settings' do
|
139
|
+
expect(instance.hosts).to eq ['10.0.0.2:9200', '10.0.0.1:9200']
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when first is not available' do
|
144
|
+
before do
|
145
|
+
client = Object.new
|
146
|
+
|
147
|
+
expect(client).to receive(:request).
|
148
|
+
with(:get, "http://#{initial_host[0]}/_nodes/_all/nothing", nil, nil, Elastics::Client::HEADERS) do
|
149
|
+
raise Timeout::Error
|
150
|
+
end
|
151
|
+
|
152
|
+
expect(client).to receive(:request).
|
153
|
+
with(:get, "http://#{initial_host[2]}/_nodes/_all/nothing", nil, nil, Elastics::Client::HEADERS) do
|
154
|
+
OpenStruct.new(status: 200, body: successful_response.to_json)
|
155
|
+
end
|
156
|
+
|
157
|
+
allow_any_instance_of(described_class).to receive(:client) { client }
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'keeps first node in @dead_hosts' do
|
161
|
+
expect(instance.hosts).to eq ['10.0.0.2:9200']
|
162
|
+
instance.send(:resurrect_cluster, 1.minute.from_now.to_i)
|
163
|
+
expect(instance.hosts).to eq ['10.0.0.2:9200', '10.0.0.1:9200']
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
108
167
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Elastics::Instrumentation do
|
4
|
+
describe '.prettify_json' do
|
5
|
+
context 'when string is json' do
|
6
|
+
it 'parses it and yields hash into block' do
|
7
|
+
result = described_class.prettify_json('{"a":1}') { |x| x.keys[0] }
|
8
|
+
expect(result).to eq 'a'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when string is multiple jsons joined with new line (bulk request)' do
|
13
|
+
it 'parses it into array and yields hashes into block one by one' do
|
14
|
+
result = described_class.prettify_json("{\"a\":1}\n{\"b\":2}") do |x|
|
15
|
+
x.keys[0]
|
16
|
+
end
|
17
|
+
expect(result).to eq "a\nb"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when string is not json' do
|
22
|
+
it 'returns original string' do
|
23
|
+
[
|
24
|
+
"{\"a\":1",
|
25
|
+
"{\"a\":1}\n{b\":2}",
|
26
|
+
"{\"a\":1}\n{\"b\":2}\n{",
|
27
|
+
'not json'
|
28
|
+
].each do |str|
|
29
|
+
expect(described_class.prettify_json(str) { raise }).to eq(str)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.prettify_body' do
|
36
|
+
context 'when body_prettifier is true' do
|
37
|
+
before { described_class.body_prettifier = true }
|
38
|
+
|
39
|
+
it 'uses JSON.pretty_generate to prettify' do
|
40
|
+
expect(JSON).to receive(:pretty_generate).with('a' => 1).and_return(1)
|
41
|
+
expect(JSON).to receive(:pretty_generate).with('b' => 2).and_return(2)
|
42
|
+
expect(described_class.prettify_body("{\"a\":1}\n{\"b\":2}")).to eq "1\n2"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '.body_prettifier=' do
|
48
|
+
context 'when new value is false/nil, Proc, or valid prettifier id' do
|
49
|
+
it 'accepts it' do
|
50
|
+
[
|
51
|
+
:ap,
|
52
|
+
true,
|
53
|
+
->(str) { str * 2 },
|
54
|
+
false,
|
55
|
+
].each { |value| described_class.body_prettifier = value }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when new value is invalid' do
|
60
|
+
it 'raises error' do
|
61
|
+
[
|
62
|
+
1,
|
63
|
+
:invalid,
|
64
|
+
Object.new,
|
65
|
+
].each do |value|
|
66
|
+
expect { described_class.body_prettifier = value }.to raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Elastics::Model::Schema do
|
4
|
+
let(:model) { Class.new.tap { |x| x.extend described_class } }
|
5
|
+
|
6
|
+
describe '#elastics_type_name' do
|
7
|
+
subject { model.elastics_type_name }
|
8
|
+
|
9
|
+
context 'when type was manually set' do
|
10
|
+
before { model.elastics_type_name = :test }
|
11
|
+
it { should be :test }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when class name does not include modules' do
|
15
|
+
before { expect(model).to receive(:name) { 'Test' } }
|
16
|
+
it { should eq 'test' }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when class name includes modules' do
|
20
|
+
before { expect(model).to receive(:name) { 'Module::Other::Index' } }
|
21
|
+
it { should eq 'index' }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Melentiev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httpclient
|
@@ -111,7 +111,6 @@ files:
|
|
111
111
|
- lib/elastics.rb
|
112
112
|
- lib/elastics/active_record.rb
|
113
113
|
- lib/elastics/active_record/helper_methods.rb
|
114
|
-
- lib/elastics/active_record/instrumentation.rb
|
115
114
|
- lib/elastics/active_record/model_schema.rb
|
116
115
|
- lib/elastics/active_record/search_result.rb
|
117
116
|
- lib/elastics/active_record/tasks_config.rb
|
@@ -120,6 +119,14 @@ files:
|
|
120
119
|
- lib/elastics/client.rb
|
121
120
|
- lib/elastics/client/bulk.rb
|
122
121
|
- lib/elastics/client/cluster.rb
|
122
|
+
- lib/elastics/instrumentation.rb
|
123
|
+
- lib/elastics/instrumentation/active_support.rb
|
124
|
+
- lib/elastics/model.rb
|
125
|
+
- lib/elastics/model/connection.rb
|
126
|
+
- lib/elastics/model/helper_methods.rb
|
127
|
+
- lib/elastics/model/schema.rb
|
128
|
+
- lib/elastics/model/skipping.rb
|
129
|
+
- lib/elastics/model/tracking.rb
|
123
130
|
- lib/elastics/query_helper.rb
|
124
131
|
- lib/elastics/railtie.rb
|
125
132
|
- lib/elastics/result.rb
|
@@ -136,6 +143,8 @@ files:
|
|
136
143
|
- spec/lib/elastics/client/bulk_spec.rb
|
137
144
|
- spec/lib/elastics/client/cluster_spec.rb
|
138
145
|
- spec/lib/elastics/client_spec.rb
|
146
|
+
- spec/lib/elastics/instrumentation_spec.rb
|
147
|
+
- spec/lib/elastics/model/schema_spec.rb
|
139
148
|
- spec/spec_helper.rb
|
140
149
|
homepage: http://github.com/printercu/elastics-rb
|
141
150
|
licenses:
|
@@ -166,4 +175,7 @@ test_files:
|
|
166
175
|
- spec/lib/elastics/client/bulk_spec.rb
|
167
176
|
- spec/lib/elastics/client/cluster_spec.rb
|
168
177
|
- spec/lib/elastics/client_spec.rb
|
178
|
+
- spec/lib/elastics/instrumentation_spec.rb
|
179
|
+
- spec/lib/elastics/model/schema_spec.rb
|
169
180
|
- spec/spec_helper.rb
|
181
|
+
has_rdoc:
|
@@ -1,71 +0,0 @@
|
|
1
|
-
module Elastics
|
2
|
-
module ActiveRecord
|
3
|
-
# To be included in `Elastics::Client`
|
4
|
-
module Instrumentation
|
5
|
-
class << self
|
6
|
-
def install
|
7
|
-
if Client.respond_to?(:prepend)
|
8
|
-
Client.prepend self
|
9
|
-
else
|
10
|
-
Client.send :include, Fallback
|
11
|
-
end
|
12
|
-
unless ::ActiveRecord::LogSubscriber < LogSubscriber
|
13
|
-
::ActiveRecord::LogSubscriber.send :include, LogSubscriber
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def http_request(*args)
|
19
|
-
ActiveSupport::Notifications.instrument 'request_elastics.active_record', args: args do
|
20
|
-
super
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# old rubies support
|
25
|
-
module Fallback
|
26
|
-
extend ActiveSupport::Concern
|
27
|
-
|
28
|
-
included do
|
29
|
-
alias_method_chain :http_request, :instrumentation
|
30
|
-
end
|
31
|
-
|
32
|
-
def http_request_with_instrumentation(*args)
|
33
|
-
ActiveSupport::Notifications.instrument 'request_elastics.active_record', args: args do
|
34
|
-
http_request_without_instrumentation(*args)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module LogSubscriber
|
41
|
-
def self.included(base)
|
42
|
-
instance_methods.each { |method| base.method_added(method) }
|
43
|
-
end
|
44
|
-
|
45
|
-
def request_elastics(event)
|
46
|
-
return unless logger.debug?
|
47
|
-
|
48
|
-
payload = event.payload[:args]
|
49
|
-
method, path, query, body, params = payload
|
50
|
-
path = '/' if path.blank?
|
51
|
-
path << "?#{query.to_param}" if query.present?
|
52
|
-
model = params[:model]
|
53
|
-
|
54
|
-
name = ""
|
55
|
-
name << "#{model.name} " if model
|
56
|
-
name << "elastics (#{event.duration.round(1)}ms)"
|
57
|
-
request = "#{method.to_s.upcase} #{path}"
|
58
|
-
request << " #{body}" if body.present?
|
59
|
-
|
60
|
-
if odd?
|
61
|
-
name = color(name, ActiveSupport::LogSubscriber::CYAN, true)
|
62
|
-
request = color(request, nil, true)
|
63
|
-
else
|
64
|
-
name = color(name, ActiveSupport::LogSubscriber::MAGENTA, true)
|
65
|
-
end
|
66
|
-
|
67
|
-
debug " #{name} #{request}"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|