diff --git a/.gitignore b/.gitignore index f36ab09..3d9fcfa 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ sequel_data.sqlite3 vendor + +typesense-data diff --git a/README.md b/README.md index 44b87d1..3652c4d 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Typesense.configuration = { }], api_key: 'your-api-key', connection_timeout_seconds: 2, - log_level: :info # Optional: Set logging level (:debug, :info, :warn, :error, :fatal, :unknown) + log_level: :info # Messages below this level will be silenced. One of (:debug, :info, :warn, :error, :fatal) } ``` diff --git a/lib/typesense-rails.rb b/lib/typesense-rails.rb index 9079485..33526d5 100644 --- a/lib/typesense-rails.rb +++ b/lib/typesense-rails.rb @@ -17,8 +17,6 @@ end require "logger" -Rails.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT)) -Rails.logger.level = Logger::WARN module Typesense class NotConfigured < StandardError; end @@ -32,6 +30,37 @@ class NoBlockGiven < StandardError; end class << self attr_reader :included_in + attr_writer :logger + + def logger + return @logger if defined?(@logger) && @logger + + rails_logger = (defined?(::Rails) && Rails.respond_to?(:logger)) ? Rails.logger : nil + @logger = rails_logger || Logger.new($stdout) + end + + def log(severity, message = nil, &block) + # If a min log level is configured, skip below-threshold messages + min_level = log_level + if min_level && !passes_min_level?(severity, min_level) + return + end + + sev_const = log_level_to_const(severity) + if logger.respond_to?(:tagged) + logger.tagged("Typesense") { logger.add(sev_const, message, &block) } + else + logger.add(sev_const, message, &block) + end + end + + def passes_min_level?(severity, min_level) + return true if min_level.nil? + + sev_const = log_level_to_const(severity) + min_const = log_level_to_const(min_level) + sev_const >= min_const + end def included(klass) @included_in ||= [] @@ -269,7 +298,7 @@ def typesense_create_collection(collection_name, settings = nil) metadata ? { "metadata" => metadata } : {} ) ) - Rails.logger.debug "Collection '#{collection_name}' created!" + Typesense.log(:debug, "Collection '#{collection_name}' created!") typesense_multi_way_synonyms(collection_name, multi_way_synonyms) if multi_way_synonyms @@ -542,7 +571,7 @@ def typesense_index_objects_async(objects, batch_size = Typesense::IndexSettings end jsonl_object = documents.join("\n") ImportJob.perform(jsonl_object, collection_obj[:alias_name], batch_size) - Rails.logger.debug "#{objects.length} objects enqueued for import into #{collection_obj[:collection_name]}" + Typesense.log(:debug, "#{objects.length} objects enqueued for import into #{collection_obj[:collection_name]}") end nil end @@ -557,7 +586,7 @@ def typesense_index_objects(objects, batch_size = Typesense::IndexSettings::DEFA end jsonl_object = documents.join("\n") import_documents(jsonl_object, "upsert", collection_obj[:alias_name], batch_size: batch_size) - Rails.logger.debug "#{objects.length} objects upserted into #{collection_obj[:collection_name]}!" + Typesense.log(:debug, "#{objects.length} objects upserted into #{collection_obj[:collection_name]}!") end nil end @@ -588,7 +617,7 @@ def typesense_index!(object) begin api_response = delete_document(object_id, collection_obj[:collection_name]) rescue Typesense::Error::ObjectNotFound => e - Rails.logger.error "Object not found in index: #{e.message}" + Typesense.log(:error, "Object not found in index: #{e.message}") end end end @@ -611,9 +640,9 @@ def typesense_remove_from_index!(object) begin delete_document(object_id, collection_obj[:alias_name]) rescue Typesense::Error::ObjectNotFound => e - Rails.logger.error "Object #{object_id} could not be removed from #{collection_obj[:collection_name]} collection! Use reindex to update the collection." + Typesense.log(:error, "Object #{object_id} could not be removed from #{collection_obj[:collection_name]} collection! Use reindex to update the collection.") end - Rails.logger.debug "Removed document with object id '#{object_id}' from #{collection_obj[:collection_name]}" + Typesense.log(:debug, "Removed document with object id '#{object_id}' from #{collection_obj[:collection_name]}") end nil end @@ -626,7 +655,7 @@ def typesense_clear_index! collection_obj = typesense_ensure_init(options, settings, false) delete_collection(collection_obj[:alias_name]) - Rails.logger.debug "Deleted #{collection_obj[:alias_name]} collection!" + Typesense.log(:debug, "Deleted #{collection_obj[:alias_name]} collection!") @typesense_indexes[settings] = nil end nil diff --git a/lib/typesense/config.rb b/lib/typesense/config.rb index 4d6698a..45c1eae 100644 --- a/lib/typesense/config.rb +++ b/lib/typesense/config.rb @@ -1,5 +1,8 @@ module Typesense module Config + @@pagination_backend = nil unless defined?(@@pagination_backend) + @@log_level = nil unless defined?(@@log_level) + @@configuration = nil unless defined?(@@configuration) def initiliaze @client = nil end @@ -13,8 +16,6 @@ def configuration=(configuration) @@pagination_backend = configuration[:pagination_backend] if configuration.key?(:pagination_backend) @@log_level = configuration[:log_level] if configuration.key?(:log_level) @@configuration = configuration - - Rails.logger.level = log_level_to_const(configuration[:log_level]) end def pagination_backend @@ -22,25 +23,38 @@ def pagination_backend end def log_level - @@log_level + defined?(@@log_level) ? @@log_level : nil end def log_level_to_const(level) - case level - when :debug - Logger::DEBUG - when :info - Logger::INFO - when :warn - Logger::WARN - when :error - Logger::ERROR - when :fatal - Logger::FATAL - when :unknown - Logger::UNKNOWN + # Be more forgiving in inputs. + # Accepts Integer (e.g., Logger::WARN), Symbol/String (e.g., :warn, "warn", "WARN", "Logger::WARN") + return level if level.is_a?(Integer) + return Logger::WARN if level.nil? + + str = level.to_s + + # Handle fully-qualified constants like "Logger::WARN" + if str.include?("::") + const = str.split("::").last + return Logger.const_get(const) if Logger.const_defined?(const) + end + + # Normalize common misnomer + upper = str.upcase + upper = "WARN" if upper == "WARNING" + return Logger.const_get(upper) if Logger.const_defined?(upper) + + # Fallback to explicit mapping + case str.downcase.to_sym + when :debug then Logger::DEBUG + when :info then Logger::INFO + when :warn, :warning then Logger::WARN + when :error then Logger::ERROR + when :fatal then Logger::FATAL + when :unknown then Logger::UNKNOWN else - Logger::WARN # default fallback + Logger::WARN end end