# Adapted from https://github.com/le0pard/mongodb_logger/ require 'mongo_request_logger/adapters/base' require 'active_support/core_ext/hash/indifferent_access' module MongoRequestLogger module Adapters class Moped < Base class << self attr_accessor :connection end def initialize(options = {}) @configuration = options.with_indifferent_access @configuration['host'] ||= '127.0.0.1' @configuration['port'] ||= '27017' @configuration['collection'] ||= 'server_log' if @configuration['url'] uri = URI.parse(@configuration['url']) @configuration['database'] = uri.path.gsub(/^\//, '') @connection ||= mongo_connection_object @connection.use @configuration['database'] @authenticated = true else @connection ||= mongo_connection_object @connection.use @configuration['database'] login end check_for_collection end def login if @configuration['username'] && @configuration['password'] # the driver stores credentials in case reconnection is required @authenticated = @connection.login(@configuration['username'], @configuration['password']) end # Allow MongoDB configured both with and without authentication begin @connection.command(ping: 1) rescue ::Moped::Errors::AuthenticationFailure => e @connection.logout @connection.command(ping: 1) end end def create_collection @connection.cluster.with_primary do |node| node.command(@configuration['database'], {create: collection_name, capped: true, size: @configuration['capsize'].to_i*1024*1024}) end end def create_index field @collection.indexes.create({field => 1}) end def insert_log_record(record) record[:_id] = ::Moped::BSON::ObjectId.new @connection.with(safe: false)[collection_name].insert(record) end def collection_stats collection_stats_hash(@connection.command(collStats: collection_name)) end def query(criteria, options={}) q = @collection.find(criteria).sort({'timestamp' => -1}) if options[:limit] q = q.limit(options[:limit]) end q end def find_by_id(id) @collection.find("_id" => ::Moped::BSON::ObjectId.from_string(id)).first end def clear! @collection.drop end private def mongo_connection_object if @configuration['hosts'] conn = ::Moped::Session.new(@configuration['hosts'].map{|(host,port)| "#{host}:#{port}"}, :timeout => 6) @configuration['replica_set'] = true elsif @configuration['url'] conn = ::Moped::Session.connect(@configuration['url']) else conn = ::Moped::Session.new(["#{@configuration['host']}:#{@configuration['port']}"], :timeout => 6) end @connection_type = conn.class MongoRequestLogger::Adapters::Moped.connection = conn conn end end end end # Adapted from Mongoid 3.0.16 lib/mongoid/railtie.rb # Unicorn clears the START_CTX when a worker is forked, so if we have # data in START_CTX then we know we're being preloaded. Unicorn does # not provide application-level hooks for executing code after the # process has forked, so we reconnect lazily. if defined?(Unicorn) && !Unicorn::HttpServer::START_CTX.empty? MongoRequestLogger::Adapters::Moped.connection.disconnect if MongoRequestLogger::Adapters::Moped.connection end # Passenger provides the :starting_worker_process event for executing # code after it has forked, so we use that and reconnect immediately. if defined?(PhusionPassenger) PhusionPassenger.on_event(:starting_worker_process) do |forked| if MongoRequestLogger::Adapters::Moped.connection && forked MongoRequestLogger::Adapters::Moped.connection.disconnect end end end