gojee-sunspot-rails 2.0.3 → 2.0.4

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.
Files changed (67) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +1 -0
  3. data/History.txt +74 -0
  4. data/LICENSE +18 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +265 -0
  7. data/Rakefile +17 -0
  8. data/TODO +8 -0
  9. data/dev_tasks/rdoc.rake +24 -0
  10. data/dev_tasks/release.rake +4 -0
  11. data/dev_tasks/spec.rake +107 -0
  12. data/dev_tasks/todo.rake +4 -0
  13. data/gemfiles/rails-2.3.14 +12 -0
  14. data/gemfiles/rails-3.0.11 +12 -0
  15. data/gemfiles/rails-3.1.3 +12 -0
  16. data/gemfiles/rails-3.2.1 +12 -0
  17. data/generators/sunspot/sunspot_generator.rb +9 -0
  18. data/generators/sunspot/templates/sunspot.yml +20 -0
  19. data/install.rb +1 -0
  20. data/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
  21. data/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +19 -0
  22. data/lib/generators/sunspot_rails.rb +9 -0
  23. data/lib/sunspot/rails/adapters.rb +83 -0
  24. data/lib/sunspot/rails/configuration.rb +376 -0
  25. data/lib/sunspot/rails/init.rb +5 -0
  26. data/lib/sunspot/rails/log_subscriber.rb +33 -0
  27. data/lib/sunspot/rails/railtie.rb +36 -0
  28. data/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
  29. data/lib/sunspot/rails/request_lifecycle.rb +36 -0
  30. data/lib/sunspot/rails/searchable.rb +491 -0
  31. data/lib/sunspot/rails/server.rb +114 -0
  32. data/lib/sunspot/rails/solr_instrumentation.rb +19 -0
  33. data/lib/sunspot/rails/solr_logging.rb +62 -0
  34. data/lib/sunspot/rails/spec_helper.rb +26 -0
  35. data/lib/sunspot/rails/stub_session_proxy.rb +142 -0
  36. data/lib/sunspot/rails/tasks.rb +84 -0
  37. data/lib/sunspot/rails.rb +69 -0
  38. data/lib/sunspot_rails.rb +12 -0
  39. data/spec/configuration_spec.rb +209 -0
  40. data/spec/model_lifecycle_spec.rb +63 -0
  41. data/spec/model_spec.rb +601 -0
  42. data/spec/rails_template/app/controllers/application_controller.rb +10 -0
  43. data/spec/rails_template/app/controllers/posts_controller.rb +6 -0
  44. data/spec/rails_template/app/models/author.rb +8 -0
  45. data/spec/rails_template/app/models/blog.rb +12 -0
  46. data/spec/rails_template/app/models/location.rb +2 -0
  47. data/spec/rails_template/app/models/photo_post.rb +2 -0
  48. data/spec/rails_template/app/models/post.rb +11 -0
  49. data/spec/rails_template/app/models/post_with_auto.rb +10 -0
  50. data/spec/rails_template/app/models/post_with_default_scope.rb +11 -0
  51. data/spec/rails_template/config/boot.rb +127 -0
  52. data/spec/rails_template/config/preinitializer.rb +22 -0
  53. data/spec/rails_template/config/routes.rb +9 -0
  54. data/spec/rails_template/config/sunspot.yml +24 -0
  55. data/spec/rails_template/db/schema.rb +27 -0
  56. data/spec/request_lifecycle_spec.rb +61 -0
  57. data/spec/schema.rb +27 -0
  58. data/spec/searchable_spec.rb +12 -0
  59. data/spec/server_spec.rb +33 -0
  60. data/spec/session_spec.rb +57 -0
  61. data/spec/shared_examples/indexed_after_save.rb +8 -0
  62. data/spec/shared_examples/not_indexed_after_save.rb +8 -0
  63. data/spec/spec_helper.rb +48 -0
  64. data/spec/stub_session_proxy_spec.rb +122 -0
  65. data/sunspot_rails.gemspec +43 -0
  66. data/tmp/.gitkeep +0 -0
  67. metadata +97 -5
@@ -0,0 +1,491 @@
1
+ module Sunspot #:nodoc:
2
+ module Rails #:nodoc:
3
+ #
4
+ # This module adds Sunspot functionality to ActiveRecord models. As well as
5
+ # providing class and instance methods, it optionally adds lifecycle hooks
6
+ # to automatically add and remove models from the Solr index as they are
7
+ # created and destroyed.
8
+ #
9
+ module Searchable
10
+ class <<self
11
+ def included(base) #:nodoc:
12
+ base.module_eval do
13
+ extend(ActsAsMethods)
14
+ end
15
+ end
16
+ end
17
+
18
+ module ActsAsMethods
19
+ #
20
+ # Makes a class searchable if it is not already, or adds search
21
+ # configuration if it is. Note that the options passed in are only used
22
+ # the first time this method is called for a particular class; so,
23
+ # search should be defined before activating any mixins that extend
24
+ # search configuration.
25
+ #
26
+ # The block passed into this method is evaluated by the
27
+ # <code>Sunspot.setup</code> method. See the Sunspot documentation for
28
+ # complete information on the functionality provided by that method.
29
+ #
30
+ # ==== Options (+options+)
31
+ #
32
+ # :auto_index<Boolean>::
33
+ # Automatically index models in Solr when they are saved.
34
+ # Default: true
35
+ # :auto_remove<Boolean>::
36
+ # Automatically remove models from the Solr index when they are
37
+ # destroyed. <b>Setting this option to +false+ is not recommended
38
+ # </b>(see the README).
39
+ # :if<Mixed>::
40
+ # Only index models in Solr if the method, proc or string evaluates
41
+ # to true (e.g. <code>:if => :should_index?</code> or <code>:if =>
42
+ # proc { |model| model.foo > 2 }</code>). Models that do not match
43
+ # the constraint will be removed from the index upon save. Multiple
44
+ # constraints can be specified by passing an array (e.g. <code>:if =>
45
+ # [:method1, :method2]</code>).
46
+ # :ignore_attribute_changes_of<Array>::
47
+ # Define attributes, that should not trigger a reindex of that
48
+ # object. Usual suspects are updated_at or counters.
49
+ # :include<Mixed>::
50
+ # Define default ActiveRecord includes, set this to allow ActiveRecord
51
+ # to load required associations when indexing. See ActiveRecord's
52
+ # documentation on eager-loading for examples on how to set this
53
+ # Default: []
54
+ # :unless<Mixed>::
55
+ # Only index models in Solr if the method, proc or string evaluates
56
+ # to false (e.g. <code>:unless => :should_not_index?</code> or <code>
57
+ # :unless => proc { |model| model.foo <= 2 }</code>). Models that do
58
+ # not match the constraint will be removed from the index upon save.
59
+ # Multiple constraints can be specified by passing an array (e.g.
60
+ # <code>:unless => [:method1, :method2]</code>).
61
+ #
62
+ # ==== Example
63
+ #
64
+ # class Post < ActiveRecord::Base
65
+ # searchable do
66
+ # text :title, :body
67
+ # string :sort_title do
68
+ # title.downcase.sub(/^(an?|the)/, '')
69
+ # end
70
+ # integer :blog_id
71
+ # time :updated_at
72
+ # end
73
+ # end
74
+ #
75
+ def searchable(options = {}, &block)
76
+ Sunspot.setup(self, &block)
77
+
78
+ if searchable?
79
+ sunspot_options[:include].concat(Util::Array(options[:include]))
80
+ else
81
+ extend ClassMethods
82
+ include InstanceMethods
83
+
84
+ class_attribute :sunspot_options
85
+
86
+ unless options[:auto_index] == false
87
+ before_save :mark_for_auto_indexing_or_removal
88
+ after_save :perform_index_tasks
89
+ end
90
+
91
+ unless options[:auto_remove] == false
92
+ after_destroy do |searchable|
93
+ searchable.remove_from_index
94
+ end
95
+ end
96
+ options[:include] = Util::Array(options[:include])
97
+
98
+ self.sunspot_options = options
99
+ end
100
+ end
101
+
102
+ #
103
+ # This method is defined on all ActiveRecord::Base subclasses. It
104
+ # is false for classes on which #searchable has not been called, and
105
+ # true for classes on which #searchable has been called.
106
+ #
107
+ # ==== Returns
108
+ #
109
+ # +false+
110
+ #
111
+ def searchable?
112
+ false
113
+ end
114
+ end
115
+
116
+ module ClassMethods
117
+ def self.extended(base) #:nodoc:
118
+ class <<base
119
+ alias_method :search, :solr_search unless method_defined? :search
120
+ alias_method :search_ids, :solr_search_ids unless method_defined? :search_ids
121
+ alias_method :remove_all_from_index, :solr_remove_all_from_index unless method_defined? :remove_all_from_index
122
+ alias_method :remove_all_from_index!, :solr_remove_all_from_index! unless method_defined? :remove_all_from_index!
123
+ alias_method :reindex, :solr_reindex unless method_defined? :reindex
124
+ alias_method :index, :solr_index unless method_defined? :index
125
+ alias_method :index_orphans, :solr_index_orphans unless method_defined? :index_orphans
126
+ alias_method :clean_index_orphans, :solr_clean_index_orphans unless method_defined? :clean_index_orphans
127
+ end
128
+ end
129
+ #
130
+ # Search for instances of this class in Solr. The block is delegated to
131
+ # the Sunspot.search method - see the Sunspot documentation for the full
132
+ # API.
133
+ #
134
+ # ==== Example
135
+ #
136
+ # Post.search(:include => [:blog]) do
137
+ # keywords 'best pizza'
138
+ # with :blog_id, 1
139
+ # order :updated_at, :desc
140
+ # facet :category_ids
141
+ # end
142
+ #
143
+ # ==== Options
144
+ #
145
+ # :include:: Specify associations to eager load
146
+ # :select:: Specify columns to select from database when loading results
147
+ #
148
+ # ==== Returns
149
+ #
150
+ # Sunspot::Search:: Object containing results, totals, facets, etc.
151
+ #
152
+ def solr_search(options = {}, &block)
153
+ solr_execute_search(options) do
154
+ Sunspot.new_search(self, &block)
155
+ end
156
+ end
157
+
158
+ #
159
+ # Get IDs of matching results without loading the result objects from
160
+ # the database. This method may be useful if search is used as an
161
+ # intermediate step in a larger find operation. The block is the same
162
+ # as the block provided to the #search method.
163
+ #
164
+ # ==== Returns
165
+ #
166
+ # Array:: Array of IDs, in the order returned by the search
167
+ #
168
+ def solr_search_ids(&block)
169
+ solr_execute_search_ids do
170
+ solr_search(&block)
171
+ end
172
+ end
173
+
174
+ #
175
+ # Remove instances of this class from the Solr index.
176
+ #
177
+ def solr_remove_all_from_index
178
+ Sunspot.remove_all(self)
179
+ end
180
+
181
+ #
182
+ # Remove all instances of this class from the Solr index and immediately
183
+ # commit.
184
+ #
185
+ #
186
+ def solr_remove_all_from_index!
187
+ Sunspot.remove_all!(self)
188
+ end
189
+
190
+ #
191
+ # Completely rebuild the index for this class. First removes all
192
+ # instances from the index, then loads records and indexes them.
193
+ #
194
+ # See #index for information on options, etc.
195
+ #
196
+ def solr_reindex(options = {})
197
+ solr_remove_all_from_index
198
+ solr_index(options)
199
+ end
200
+
201
+ #
202
+ # Add/update all existing records in the Solr index. The
203
+ # +batch_size+ argument specifies how many records to load out of the
204
+ # database at a time. The default batch size is 50; if nil is passed,
205
+ # records will not be indexed in batches. By default, a commit is issued
206
+ # after each batch; passing +false+ for +batch_commit+ will disable
207
+ # this, and only issue a commit at the end of the process. If associated
208
+ # objects need to indexed also, you can specify +include+ in format
209
+ # accepted by ActiveRecord to improve your sql select performance
210
+ #
211
+ # ==== Options (passed as a hash)
212
+ #
213
+ # batch_size<Integer>:: Batch size with which to load records. Passing
214
+ # 'nil' will skip batches. Default is 50.
215
+ # batch_commit<Boolean>:: Flag signalling if a commit should be done after
216
+ # after each batch is indexed, default is 'true'
217
+ # include<Mixed>:: include option to be passed to the ActiveRecord find,
218
+ # used for including associated objects that need to be
219
+ # indexed with the parent object, accepts all formats
220
+ # ActiveRecord::Base.find does
221
+ # first_id:: The lowest possible ID for this class. Defaults to 0, which
222
+ # is fine for integer IDs; string primary keys will need to
223
+ # specify something reasonable here.
224
+ #
225
+ # ==== Examples
226
+ #
227
+ # # index in batches of 50, commit after each
228
+ # Post.index
229
+ #
230
+ # # index all rows at once, then commit
231
+ # Post.index(:batch_size => nil)
232
+ #
233
+ # # index in batches of 50, commit when all batches complete
234
+ # Post.index(:batch_commit => false)
235
+ #
236
+ # # include the associated +author+ object when loading to index
237
+ # Post.index(:include => :author)
238
+ #
239
+ def solr_index(opts={})
240
+ options = {
241
+ :batch_size => Sunspot.config.indexing.default_batch_size,
242
+ :batch_commit => true,
243
+ :include => self.sunspot_options[:include],
244
+ :start => opts.delete(:first_id) || 0
245
+ }.merge(opts)
246
+ find_in_batch_options = {
247
+ :include => options[:include],
248
+ :batch_size => options[:batch_size],
249
+ :start => options[:first_id]
250
+ }
251
+ progress_bar = options[:progress_bar]
252
+ if options[:batch_size]
253
+ batch_counter = 0
254
+ find_in_batches(find_in_batch_options) do |records|
255
+ solr_benchmark options[:batch_size], batch_counter do
256
+ Sunspot.index(records.select { |model| model.indexable? })
257
+ Sunspot.commit if options[:batch_commit]
258
+ end
259
+ # track progress
260
+ progress_bar.increment!(records.length) if progress_bar
261
+ batch_counter += 1
262
+ end
263
+ else
264
+ records = all(:include => options[:include]).select { |model| model.indexable? }
265
+ Sunspot.index!(records)
266
+ end
267
+ # perform a final commit if not committing in batches
268
+ Sunspot.commit unless options[:batch_commit]
269
+ end
270
+
271
+ #
272
+ # Return the IDs of records of this class that are indexed in Solr but
273
+ # do not exist in the database. Under normal circumstances, this should
274
+ # never happen, but this method is provided in case something goes
275
+ # wrong. Usually you will want to rectify the situation by calling
276
+ # #clean_index_orphans or #reindex
277
+ #
278
+ # ==== Options (passed as a hash)
279
+ #
280
+ # batch_size<Integer>:: Batch size with which to load records. Passing
281
+ # Default is 1000 (from ActiveRecord).
282
+ #
283
+ # ==== Returns
284
+ #
285
+ # Array:: Collection of IDs that exist in Solr but not in the database
286
+ def solr_index_orphans(opts={})
287
+ batch_size = opts[:batch_size] || Sunspot.config.indexing.default_batch_size
288
+ count = self.count
289
+ indexed_ids = solr_search_ids { paginate(:page => 1, :per_page => count) }.to_set
290
+ find_each(:select => 'id', :batch_size => batch_size) do |object|
291
+ indexed_ids.delete(object.id)
292
+ end
293
+ indexed_ids.to_a
294
+ end
295
+
296
+ #
297
+ # Find IDs of records of this class that are indexed in Solr but do not
298
+ # exist in the database, and remove them from Solr. Under normal
299
+ # circumstances, this should not be necessary; this method is provided
300
+ # in case something goes wrong.
301
+ #
302
+ # ==== Options (passed as a hash)
303
+ #
304
+ # batch_size<Integer>:: Batch size with which to load records
305
+ # Default is 50
306
+ #
307
+ def solr_clean_index_orphans(opts={})
308
+ solr_index_orphans(opts).each do |id|
309
+ new do |fake_instance|
310
+ fake_instance.id = id
311
+ end.solr_remove_from_index
312
+ end
313
+ end
314
+
315
+ #
316
+ # Classes that have been defined as searchable return +true+ for this
317
+ # method.
318
+ #
319
+ # ==== Returns
320
+ #
321
+ # +true+
322
+ #
323
+ def searchable?
324
+ true
325
+ end
326
+
327
+ def solr_execute_search(options = {})
328
+ options.assert_valid_keys(:include, :select)
329
+ search = yield
330
+ unless options.empty?
331
+ search.build do |query|
332
+ if options[:include]
333
+ query.data_accessor_for(self).include = options[:include]
334
+ end
335
+ if options[:select]
336
+ query.data_accessor_for(self).select = options[:select]
337
+ end
338
+ end
339
+ end
340
+ search.execute
341
+ end
342
+
343
+ def solr_execute_search_ids(options = {})
344
+ search = yield
345
+ search.raw_results.map { |raw_result| raw_result.primary_key.to_i }
346
+ end
347
+
348
+ protected
349
+
350
+ #
351
+ # Does some logging for benchmarking indexing performance
352
+ #
353
+ def solr_benchmark(batch_size, counter, &block)
354
+ start = Time.now
355
+ logger.info("[#{Time.now}] Start Indexing")
356
+ yield
357
+ elapsed = Time.now-start
358
+ logger.info("[#{Time.now}] Completed Indexing. Rows indexed #{counter * batch_size}. Rows/sec: #{batch_size/elapsed.to_f} (Elapsed: #{elapsed} sec.)")
359
+ end
360
+
361
+ end
362
+
363
+ module InstanceMethods
364
+ def self.included(base) #:nodoc:
365
+ base.module_eval do
366
+ alias_method :index, :solr_index unless method_defined? :index
367
+ alias_method :index!, :solr_index! unless method_defined? :index!
368
+ alias_method :remove_from_index, :solr_remove_from_index unless method_defined? :remove_from_index
369
+ alias_method :remove_from_index!, :solr_remove_from_index! unless method_defined? :remove_from_index!
370
+ alias_method :more_like_this, :solr_more_like_this unless method_defined? :more_like_this
371
+ alias_method :more_like_this_ids, :solr_more_like_this_ids unless method_defined? :more_like_this_ids
372
+ end
373
+ end
374
+ #
375
+ # Index the model in Solr. If the model is already indexed, it will be
376
+ # updated. Using the defaults, you will usually not need to call this
377
+ # method, as models are indexed automatically when they are created or
378
+ # updated. If you have disabled automatic indexing (see
379
+ # ClassMethods#searchable), this method allows you to manage indexing
380
+ # manually.
381
+ #
382
+ def solr_index
383
+ Sunspot.index(self)
384
+ end
385
+
386
+ #
387
+ # Index the model in Solr and immediately commit. See #index
388
+ #
389
+ def solr_index!
390
+ Sunspot.index!(self)
391
+ end
392
+
393
+ #
394
+ # Remove the model from the Solr index. Using the defaults, this should
395
+ # not be necessary, as models will automatically be removed from the
396
+ # index when they are destroyed. If you disable automatic removal
397
+ # (which is not recommended!), you can use this method to manage removal
398
+ # manually.
399
+ #
400
+ def solr_remove_from_index
401
+ Sunspot.remove(self)
402
+ end
403
+
404
+ #
405
+ # Remove the model from the Solr index and commit immediately. See
406
+ # #remove_from_index
407
+ #
408
+ def solr_remove_from_index!
409
+ Sunspot.remove!(self)
410
+ end
411
+
412
+ def solr_more_like_this(*args, &block)
413
+ options = args.extract_options!
414
+ self.class.solr_execute_search(options) do
415
+ Sunspot.new_more_like_this(self, *args, &block)
416
+ end
417
+ end
418
+
419
+ def solr_more_like_this_ids(&block)
420
+ self.class.solr_execute_search_ids do
421
+ solr_more_like_this(&block)
422
+ end
423
+ end
424
+
425
+ def indexable?
426
+ # options[:if] is not specified or they successfully pass
427
+ if_passes = self.class.sunspot_options[:if].nil? ||
428
+ constraint_passes?(self.class.sunspot_options[:if])
429
+
430
+ # options[:unless] is not specified or they successfully pass
431
+ unless_passes = self.class.sunspot_options[:unless].nil? ||
432
+ !constraint_passes?(self.class.sunspot_options[:unless])
433
+
434
+ if_passes and unless_passes
435
+ end
436
+
437
+ private
438
+
439
+ def constraint_passes?(constraint)
440
+ case constraint
441
+ when Symbol
442
+ self.__send__(constraint)
443
+ when String
444
+ self.__send__(constraint.to_sym)
445
+ when Enumerable
446
+ # All constraints must pass
447
+ constraint.all? { |inner_constraint| constraint_passes?(inner_constraint) }
448
+ else
449
+ if constraint.respond_to?(:call) # could be a Proc or anything else that responds to call
450
+ constraint.call(self)
451
+ else
452
+ raise ArgumentError, "Unknown constraint type: #{constraint} (#{constraint.class})"
453
+ end
454
+ end
455
+ end
456
+
457
+ def mark_for_auto_indexing_or_removal
458
+ if indexable?
459
+ # :if/:unless constraints pass or were not present
460
+
461
+ @marked_for_auto_indexing =
462
+ if !new_record? && ignore_attributes = self.class.sunspot_options[:ignore_attribute_changes_of]
463
+ !(changed.map { |attr| attr.to_sym } - ignore_attributes).blank?
464
+ else
465
+ true
466
+ end
467
+
468
+ @marked_for_auto_removal = false
469
+ else
470
+ # :if/:unless constraints did not pass; do not auto index and
471
+ # actually go one step further by removing it from the index
472
+ @marked_for_auto_indexing = false
473
+ @marked_for_auto_removal = true
474
+ end
475
+
476
+ true
477
+ end
478
+
479
+ def perform_index_tasks
480
+ if @marked_for_auto_indexing
481
+ solr_index
482
+ remove_instance_variable(:@marked_for_auto_indexing)
483
+ elsif @marked_for_auto_removal
484
+ solr_remove_from_index
485
+ remove_instance_variable(:@marked_for_auto_removal)
486
+ end
487
+ end
488
+ end
489
+ end
490
+ end
491
+ end
@@ -0,0 +1,114 @@
1
+ module Sunspot
2
+ module Rails
3
+ class Server < Sunspot::Solr::Server
4
+ # ActiveSupport log levels are integers; this array maps them to the
5
+ # appropriate java.util.logging.Level constant
6
+ LOG_LEVELS = %w(FINE INFO WARNING SEVERE SEVERE INFO)
7
+
8
+ #
9
+ # Directory in which to store PID files
10
+ #
11
+ def pid_dir
12
+ configuration.pid_dir || File.join(::Rails.root, 'tmp', 'pids')
13
+ end
14
+
15
+ #
16
+ # Name of the PID file
17
+ #
18
+ def pid_file
19
+ "sunspot-solr-#{::Rails.env}.pid"
20
+ end
21
+
22
+ #
23
+ # Directory to store lucene index data files
24
+ #
25
+ # ==== Returns
26
+ #
27
+ # String:: data_path
28
+ #
29
+ def solr_data_dir
30
+ configuration.data_path
31
+ end
32
+
33
+ #
34
+ # Directory to use for Solr home.
35
+ #
36
+ def solr_home
37
+ File.join(configuration.solr_home)
38
+ end
39
+
40
+ #
41
+ # Solr start jar
42
+ #
43
+ def solr_jar
44
+ configuration.solr_jar || super
45
+ end
46
+
47
+ #
48
+ # Address on which to run Solr
49
+ #
50
+ def bind_address
51
+ configuration.bind_address
52
+ end
53
+
54
+ #
55
+ # Port on which to run Solr
56
+ #
57
+ def port
58
+ configuration.port
59
+ end
60
+
61
+ #
62
+ # Severity level for logging. This is based on the severity level for the
63
+ # Rails logger.
64
+ #
65
+ def log_level
66
+ LOG_LEVELS[::Rails.logger.level]
67
+ end
68
+
69
+ #
70
+ # Log file for Solr. File is in the rails log/ directory.
71
+ #
72
+ def log_file
73
+ File.join(::Rails.root, 'log', "sunspot-solr-#{::Rails.env}.log")
74
+ end
75
+
76
+ #
77
+ # Minimum Java heap size for Solr
78
+ #
79
+ def min_memory
80
+ configuration.min_memory
81
+ end
82
+
83
+ #
84
+ # Maximum Java heap size for Solr
85
+ #
86
+ def max_memory
87
+ configuration.max_memory
88
+ end
89
+
90
+ #
91
+ # A boolean value indicating whether or not solr is being run with multiple cores
92
+ #
93
+ def multicore
94
+ !!configuration.multicore
95
+ end
96
+
97
+ private
98
+
99
+ #
100
+ # access to the Sunspot::Rails::Configuration, defined in
101
+ # sunspot.yml. Use Sunspot::Rails.configuration if you want
102
+ # to access the configuration directly.
103
+ #
104
+ # ==== returns
105
+ #
106
+ # Sunspot::Rails::Configuration:: configuration
107
+ #
108
+ def configuration
109
+ Sunspot::Rails.configuration
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,19 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SolrInstrumentation
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :execute, :as_instrumentation
8
+ end
9
+
10
+
11
+ def execute_with_as_instrumentation(path, params={}, *extra)
12
+ ActiveSupport::Notifications.instrument("request.rsolr",
13
+ {:path => path, :parameters => params}) do
14
+ execute_without_as_instrumentation(path, params, *extra)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SolrLogging
4
+
5
+ class <<self
6
+ def included(base)
7
+ base.alias_method_chain :execute, :rails_logging
8
+ end
9
+ end
10
+
11
+ COMMIT = %r{<commit/>}
12
+
13
+ def execute_with_rails_logging(client, request_context)
14
+ body = (request_context[:data]||"").dup
15
+ action = request_context[:path].capitalize
16
+ if body =~ COMMIT
17
+ action = "Commit"
18
+ body = ""
19
+ end
20
+ body = body[0, 800] + '...' if body.length > 800
21
+
22
+ # Make request and log.
23
+ response = nil
24
+ begin
25
+ ms = Benchmark.ms do
26
+ response = execute_without_rails_logging(client, request_context)
27
+ end
28
+ log_name = 'Solr %s (%.1fms)' % [action, ms]
29
+ ::Rails.logger.debug(format_log_entry(log_name, body))
30
+ rescue Exception => e
31
+ log_name = 'Solr %s (Error)' % [action]
32
+ ::Rails.logger.error(format_log_entry(log_name, body))
33
+ raise e
34
+ end
35
+
36
+ response
37
+ end
38
+
39
+ private
40
+
41
+ def format_log_entry(message, dump = nil)
42
+ @colorize_logging ||= begin
43
+ ::Rails.application.config.colorize_logging # Rails 3
44
+ rescue NoMethodError
45
+ ActiveRecord::Base.colorize_logging # Rails 2
46
+ end
47
+ if @colorize_logging
48
+ message_color, dump_color = "4;32;1", "0;1"
49
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
50
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
51
+ log_entry
52
+ else
53
+ "%s %s" % [message, dump]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ RSolr::Connection.module_eval do
61
+ include Sunspot::Rails::SolrLogging
62
+ end