lib/and-son/client.rb in and-son-0.2.1 vs lib/and-son/client.rb in and-son-0.3.0
- old
+ new
@@ -1,5 +1,7 @@
+require 'benchmark'
+require 'logger'
require 'ostruct'
require 'sanford-protocol'
require 'and-son/connection'
require 'and-son/response'
require 'and-son/stored_responses'
@@ -12,20 +14,24 @@
# use `tap` to return whatever instance `self.call_runner` returns so you
# can method-chain. `self.call_runner` returns a new runner instance if
# called on a client, but returns the chained instance if called on a runner
def timeout(seconds)
- self.call_runner.tap{|r| r.timeout_value = seconds.to_f}
+ self.call_runner.tap{|r| r.timeout_value = seconds.to_f }
end
def params(hash = nil)
if !hash.kind_of?(Hash)
raise ArgumentError, "expected params to be a Hash instead of a #{hash.class}"
end
self.call_runner.tap{|r| r.params_value.merge!(self.stringify_keys(hash)) }
end
+ def logger(passed_logger)
+ self.call_runner.tap{|r| r.logger_value = passed_logger }
+ end
+
protected
def stringify_keys(hash)
hash.inject({}){|h, (k, v)| h.merge({ k.to_s => v }) }
end
@@ -53,30 +59,36 @@
:host => host,
:port => port,
:version => version,
:timeout_value => (ENV['ANDSON_TIMEOUT'] || DEFAULT_TIMEOUT).to_f,
:params_value => {},
+ :logger_value => NullLogger.new,
:responses => @responses,
})
end
end
class CallRunner < OpenStruct
- # {:host, :port, :version, :timeout_value, :params_value, :responses}
+ # { :host, :port, :version, :timeout_value, :params_value, :logger_value,
+ # :responses }
include CallRunnerMethods
# chain runner methods by returning itself
def call_runner; self; end
def call(name, params = nil)
params ||= {}
if !params.kind_of?(Hash)
raise ArgumentError, "expected params to be a Hash instead of a #{params.class}"
end
- client_response = self.responses.find(name, params) if ENV['ANDSON_TEST_MODE']
- client_response ||= self.call!(name, params)
+ client_response = nil
+ benchmark = Benchmark.measure do
+ client_response = self.responses.find(name, params) if ENV['ANDSON_TEST_MODE']
+ client_response ||= self.call!(name, params)
+ end
+ self.logger_value.info("[AndSon] #{summary_line(name, params, benchmark, client_response)}")
if block_given?
yield client_response.protocol_response
else
client_response.data
end
@@ -84,12 +96,66 @@
def call!(name, params)
call_params = self.params_value.merge(params)
AndSon::Connection.new(host, port).open do |connection|
connection.write(Sanford::Protocol::Request.new(version, name, call_params).to_hash)
- AndSon::Response.parse(connection.read(timeout_value))
+ if !connection.peek(timeout_value).empty?
+ AndSon::Response.parse(connection.read(timeout_value))
+ else
+ raise AndSon::ConnectionClosedError.new
+ end
end
end
+ protected
+
+ def summary_line(name, params, benchmark, client_response)
+ response = client_response.protocol_response
+ SummaryLine.new.tap do |line|
+ line.add 'host', "#{self.host}:#{self.port}"
+ line.add 'version', self.version
+ line.add 'service', name
+ line.add 'params', params
+ line.add 'status', response.code
+ line.add 'duration', self.round_time(benchmark.real)
+ end
+ end
+
+ ROUND_PRECISION = 2
+ ROUND_MODIFIER = 10 ** ROUND_PRECISION
+ def round_time(time_in_seconds)
+ (time_in_seconds * 1000 * ROUND_MODIFIER).to_i / ROUND_MODIFIER.to_f
+ end
+
+ end
+
+ class SummaryLine
+
+ def initialize
+ @hash = {}
+ end
+
+ def add(key, value)
+ @hash[key] = value.inspect if value
+ end
+
+ def to_s
+ [ 'host', 'version', 'service', 'status', 'duration', 'params' ].map do |key|
+ "#{key}=#{@hash[key]}" if @hash[key]
+ end.compact.join(" ")
+ end
+
+ end
+
+ class ConnectionClosedError < RuntimeError
+ def initialize
+ super "The server closed the connection, no response was written."
+ end
+ end
+
+ class NullLogger
+ ::Logger::Severity.constants.each do |name|
+ define_method(name.downcase){|*args| } # no-op
+ end
end
end