elastics 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|