newrelic_rpm 3.7.0.177 → 3.7.1.180
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +28 -1
- data/lib/new_relic/agent.rb +1 -2
- data/lib/new_relic/agent/agent.rb +28 -10
- data/lib/new_relic/agent/agent_logger.rb +4 -3
- data/lib/new_relic/agent/audit_logger.rb +5 -8
- data/lib/new_relic/agent/configuration/default_source.rb +24 -0
- data/lib/new_relic/agent/cross_app_tracing.rb +21 -15
- data/lib/new_relic/agent/datastores/mongo.rb +25 -0
- data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +25 -0
- data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +189 -0
- data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +39 -0
- data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +52 -0
- data/lib/new_relic/agent/harvester.rb +55 -0
- data/lib/new_relic/agent/instrumentation/mongo.rb +139 -0
- data/lib/new_relic/agent/instrumentation/net.rb +6 -11
- data/lib/new_relic/agent/supported_versions.rb +9 -5
- data/lib/new_relic/agent/transaction_sampler.rb +4 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/versions.rake +1 -1
- data/test/agent_helper.rb +4 -0
- data/test/environments/norails/Gemfile +3 -0
- data/test/environments/rails40/Gemfile +5 -1
- data/test/flaky_proxy/Gemfile +3 -0
- data/test/flaky_proxy/README.md +82 -0
- data/test/flaky_proxy/lib/flaky_proxy.rb +22 -0
- data/test/flaky_proxy/lib/flaky_proxy/connection.rb +45 -0
- data/test/flaky_proxy/lib/flaky_proxy/http_message.rb +105 -0
- data/test/flaky_proxy/lib/flaky_proxy/proxy.rb +42 -0
- data/test/flaky_proxy/lib/flaky_proxy/rule.rb +75 -0
- data/test/flaky_proxy/lib/flaky_proxy/rule_set.rb +37 -0
- data/test/flaky_proxy/lib/flaky_proxy/server.rb +22 -0
- data/test/flaky_proxy/script/flaky_proxy +39 -0
- data/test/helpers/exceptions.rb +16 -0
- data/test/helpers/mongo_metric_builder.rb +29 -0
- data/test/multiverse/lib/multiverse/suite.rb +1 -0
- data/test/multiverse/suites/curb/curb_test.rb +0 -1
- data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +4 -3
- data/test/multiverse/suites/excon/excon_test.rb +0 -1
- data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -1
- data/test/multiverse/suites/mongo/Envfile +66 -0
- data/test/multiverse/suites/mongo/config/newrelic.yml +19 -0
- data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +418 -0
- data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +36 -0
- data/test/multiverse/suites/net_http/net_http_test.rb +2 -4
- data/test/multiverse/suites/rails/Envfile +4 -4
- data/test/multiverse/suites/rails/config/newrelic.yml +1 -1
- data/test/multiverse/suites/rails/error_tracing_test.rb +7 -7
- data/test/multiverse/suites/sidekiq/Envfile +1 -1
- data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -1
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +5 -3
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +5 -3
- data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -1
- data/test/new_relic/agent/agent_logger_test.rb +9 -1
- data/test/new_relic/agent/agent_test.rb +66 -1
- data/test/new_relic/agent/agent_test_controller.rb +1 -2
- data/test/new_relic/agent/audit_logger_test.rb +12 -4
- data/test/new_relic/agent/configuration/orphan_configuration_test.rb +11 -2
- data/test/new_relic/agent/cpu_sampler_test.rb +1 -0
- data/test/new_relic/agent/cross_app_tracing_test.rb +60 -0
- data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +43 -0
- data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +301 -0
- data/test/new_relic/agent/datastores/mongo/obfuscator_test.rb +91 -0
- data/test/new_relic/agent/datastores/mongo/statement_formatter_test.rb +71 -0
- data/test/new_relic/agent/harvester_test.rb +85 -0
- data/test/new_relic/agent/transaction_sampler_test.rb +5 -0
- data/test/new_relic/agent/worker_loop_test.rb +3 -5
- data/test/new_relic/http_client_test_cases.rb +65 -81
- data/test/new_relic/noticed_error_test.rb +14 -16
- data/test/performance/lib/performance.rb +1 -0
- data/test/performance/lib/performance/console_reporter.rb +6 -2
- data/test/performance/lib/performance/instrumentor.rb +1 -15
- data/test/performance/lib/performance/platform.rb +35 -0
- data/test/performance/lib/performance/test_case.rb +16 -1
- data/test/performance/suites/marshalling.rb +73 -0
- metadata +48 -19
- metadata.gz.sig +1 -2
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
module Datastores
|
8
|
+
module Mongo
|
9
|
+
module Obfuscator
|
10
|
+
|
11
|
+
WHITELIST = [:operation].freeze
|
12
|
+
|
13
|
+
def self.obfuscate_statement(source, whitelist=WHITELIST)
|
14
|
+
obfuscated = {}
|
15
|
+
source.each do |key, value|
|
16
|
+
if whitelist.include?(key)
|
17
|
+
obfuscated[key] = value
|
18
|
+
else
|
19
|
+
obfuscated[key] = obfuscate_value(value, whitelist)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
obfuscated
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.obfuscate_value(value, whitelist)
|
27
|
+
if value.is_a?(Hash)
|
28
|
+
obfuscate_statement(value, whitelist)
|
29
|
+
elsif value.is_a?(Array)
|
30
|
+
value.map {|v| obfuscate_value(v, whitelist)}
|
31
|
+
else
|
32
|
+
'?'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
require 'new_relic/agent/datastores/mongo/obfuscator'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
module Datastores
|
10
|
+
module Mongo
|
11
|
+
module StatementFormatter
|
12
|
+
|
13
|
+
PLAINTEXT_KEYS = [
|
14
|
+
:database,
|
15
|
+
:collection,
|
16
|
+
:operation,
|
17
|
+
:fields,
|
18
|
+
:skip,
|
19
|
+
:limit,
|
20
|
+
:order
|
21
|
+
]
|
22
|
+
|
23
|
+
OBFUSCATE_KEYS = [
|
24
|
+
:selector
|
25
|
+
]
|
26
|
+
|
27
|
+
def self.format(statement)
|
28
|
+
return nil unless NewRelic::Agent.config[:'mongo.capture_queries']
|
29
|
+
|
30
|
+
result = {}
|
31
|
+
PLAINTEXT_KEYS.each do |key|
|
32
|
+
result[key] = statement[key] if statement.key?(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
OBFUSCATE_KEYS.each do |key|
|
36
|
+
if statement.key?(key)
|
37
|
+
obfuscated = obfuscate(statement[key])
|
38
|
+
result[key] = obfuscated if obfuscated
|
39
|
+
end
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.obfuscate(statement)
|
45
|
+
statement = Obfuscator.obfuscate_statement(statement) if NewRelic::Agent.config[:'mongo.obfuscate_queries']
|
46
|
+
statement
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
class Harvester
|
8
|
+
attr_accessor :starting_pid
|
9
|
+
|
10
|
+
# Inject target for after_fork call to avoid spawning thread in tests
|
11
|
+
def initialize(events, after_forker=NewRelic::Agent)
|
12
|
+
@starting_pid = Process.pid
|
13
|
+
@after_forker = after_forker
|
14
|
+
@lock = Mutex.new
|
15
|
+
|
16
|
+
if events
|
17
|
+
events.subscribe(:start_transaction, &method(:on_transaction))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_transaction(*_)
|
22
|
+
return unless restart_in_children_enabled? && needs_restart?
|
23
|
+
|
24
|
+
needs_thread_start = false
|
25
|
+
@lock.synchronize do
|
26
|
+
needs_thread_start = needs_restart?
|
27
|
+
mark_started
|
28
|
+
end
|
29
|
+
|
30
|
+
if needs_thread_start
|
31
|
+
restart_harvest_thread
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mark_started(pid = Process.pid)
|
36
|
+
@starting_pid = pid
|
37
|
+
end
|
38
|
+
|
39
|
+
def needs_restart?(pid = Process.pid)
|
40
|
+
@starting_pid != pid
|
41
|
+
end
|
42
|
+
|
43
|
+
def restart_in_children_enabled?
|
44
|
+
NewRelic::Agent.config[:restart_thread_in_children]
|
45
|
+
end
|
46
|
+
|
47
|
+
def restart_harvest_thread
|
48
|
+
# Daemonize reports thread as still alive when it isn't... whack!
|
49
|
+
NewRelic::Agent.instance.instance_variable_set(:@worker_thread, nil)
|
50
|
+
@after_forker.after_fork(:force_reconnect => true)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
DependencyDetection.defer do
|
6
|
+
named :mongo
|
7
|
+
|
8
|
+
depends_on do
|
9
|
+
if defined?(::Mongo) && defined?(::Mongo::Logging)
|
10
|
+
true
|
11
|
+
else
|
12
|
+
if defined?(::Mongo)
|
13
|
+
NewRelic::Agent.logger.info 'Mongo instrumentation requires Mongo::Logging'
|
14
|
+
end
|
15
|
+
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
depends_on do
|
21
|
+
require 'new_relic/agent/datastores/mongo'
|
22
|
+
NewRelic::Agent::Datastores::Mongo.is_supported_version?
|
23
|
+
end
|
24
|
+
|
25
|
+
executes do
|
26
|
+
NewRelic::Agent.logger.info 'Installing Mongo instrumentation'
|
27
|
+
install_mongo_instrumentation
|
28
|
+
end
|
29
|
+
|
30
|
+
def install_mongo_instrumentation
|
31
|
+
instrument_mongo_logging
|
32
|
+
instrument_save
|
33
|
+
instrument_ensure_index
|
34
|
+
end
|
35
|
+
|
36
|
+
def instrument_mongo_logging
|
37
|
+
::Mongo::Logging.class_eval do
|
38
|
+
include NewRelic::Agent::MethodTracer
|
39
|
+
require 'new_relic/agent/datastores/mongo/metric_generator'
|
40
|
+
require 'new_relic/agent/datastores/mongo/statement_formatter'
|
41
|
+
|
42
|
+
def instrument_with_new_relic_trace(name, payload = {}, &block)
|
43
|
+
metrics = NewRelic::Agent::Datastores::Mongo::MetricGenerator.generate_metrics_for(name, payload)
|
44
|
+
|
45
|
+
trace_execution_scoped(metrics) do
|
46
|
+
t0 = Time.now
|
47
|
+
result = instrument_without_new_relic_trace(name, payload, &block)
|
48
|
+
|
49
|
+
payload[:operation] = name
|
50
|
+
statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(payload)
|
51
|
+
if statement
|
52
|
+
NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
|
53
|
+
end
|
54
|
+
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
::Mongo::Collection.class_eval { include Mongo::Logging; }
|
60
|
+
::Mongo::Connection.class_eval { include Mongo::Logging; }
|
61
|
+
::Mongo::Cursor.class_eval { include Mongo::Logging; }
|
62
|
+
|
63
|
+
alias_method :instrument_without_new_relic_trace, :instrument
|
64
|
+
alias_method :instrument, :instrument_with_new_relic_trace
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def instrument_save
|
69
|
+
::Mongo::Collection.class_eval do
|
70
|
+
include NewRelic::Agent::MethodTracer
|
71
|
+
require 'new_relic/agent/datastores/mongo/metric_generator'
|
72
|
+
require 'new_relic/agent/datastores/mongo/statement_formatter'
|
73
|
+
|
74
|
+
def save_with_new_relic_trace(doc, opts = {}, &block)
|
75
|
+
metrics = NewRelic::Agent::Datastores::Mongo::MetricGenerator.generate_metrics_for(:save, { :collection => self.name })
|
76
|
+
|
77
|
+
trace_execution_scoped(metrics) do
|
78
|
+
t0 = Time.now
|
79
|
+
|
80
|
+
transaction_state = NewRelic::Agent::TransactionState.get
|
81
|
+
transaction_state.push_traced(false)
|
82
|
+
|
83
|
+
begin
|
84
|
+
result = save_without_new_relic_trace(doc, opts, &block)
|
85
|
+
ensure
|
86
|
+
transaction_state.pop_traced
|
87
|
+
end
|
88
|
+
|
89
|
+
doc[:operation] = :save
|
90
|
+
statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(doc)
|
91
|
+
if statement
|
92
|
+
NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
|
93
|
+
end
|
94
|
+
|
95
|
+
result
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
alias_method :save_without_new_relic_trace, :save
|
100
|
+
alias_method :save, :save_with_new_relic_trace
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def instrument_ensure_index
|
105
|
+
::Mongo::Collection.class_eval do
|
106
|
+
include NewRelic::Agent::MethodTracer
|
107
|
+
require 'new_relic/agent/datastores/mongo/metric_generator'
|
108
|
+
require 'new_relic/agent/datastores/mongo/statement_formatter'
|
109
|
+
|
110
|
+
def ensure_index_with_new_relic_trace(spec, opts = {}, &block)
|
111
|
+
metrics = NewRelic::Agent::Datastores::Mongo::MetricGenerator.generate_metrics_for(:ensureIndex, { :collection => self.name })
|
112
|
+
|
113
|
+
trace_execution_scoped(metrics) do
|
114
|
+
t0 = Time.now
|
115
|
+
|
116
|
+
transaction_state = NewRelic::Agent::TransactionState.get
|
117
|
+
transaction_state.push_traced(false)
|
118
|
+
|
119
|
+
begin
|
120
|
+
result = save_without_new_relic_trace(spec, opts, &block)
|
121
|
+
ensure
|
122
|
+
transaction_state.pop_traced
|
123
|
+
end
|
124
|
+
|
125
|
+
spec[:operation] = :ensureIndex
|
126
|
+
statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(spec)
|
127
|
+
if statement
|
128
|
+
NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
|
129
|
+
end
|
130
|
+
|
131
|
+
result
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
alias_method :ensure_index_without_new_relic_trace, :ensure_index
|
136
|
+
alias_method :ensure_index, :ensure_index_with_new_relic_trace
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -17,20 +17,15 @@ DependencyDetection.defer do
|
|
17
17
|
|
18
18
|
executes do
|
19
19
|
class Net::HTTP
|
20
|
-
# Instrument outgoing HTTP requests
|
21
|
-
#
|
22
|
-
# If request is called when not the connection isn't started, request
|
23
|
-
# will call back into itself (via a start block).
|
24
|
-
#
|
25
|
-
# Don't tracing until the inner call then to avoid double-counting.
|
26
20
|
def request_with_newrelic_trace(request, *args, &block)
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
wrapped_request = NewRelic::Agent::HTTPClients::NetHTTPRequest.new(self, request)
|
22
|
+
|
23
|
+
NewRelic::Agent::CrossAppTracing.trace_http_request( wrapped_request ) do
|
24
|
+
# RUBY-1244 Disable further tracing in request to avoid double
|
25
|
+
# counting if connection wasn't started (which calls request again).
|
26
|
+
NewRelic::Agent.disable_all_tracing do
|
30
27
|
request_without_newrelic_trace( request, *args, &block )
|
31
28
|
end
|
32
|
-
else
|
33
|
-
request_without_newrelic_trace( request, *args, &block )
|
34
29
|
end
|
35
30
|
end
|
36
31
|
|
@@ -32,12 +32,9 @@ module NewRelic
|
|
32
32
|
{
|
33
33
|
:type => :ruby,
|
34
34
|
:name => "Rubinius",
|
35
|
-
:
|
35
|
+
:supported => ["~> 2.2.1"],
|
36
36
|
:url => "http://rubini.us",
|
37
|
-
:feed => "http://rubini.us/feed/atom.xml"
|
38
|
-
:notes => [
|
39
|
-
"Support for Rubinius 2.x is considered experimental.",
|
40
|
-
"Consider using the latest for best results, and watch http://docs.newrelic.com/docs/ruby/rubinius for updates."]
|
37
|
+
:feed => "http://rubini.us/feed/atom.xml"
|
41
38
|
},
|
42
39
|
|
43
40
|
# App servers
|
@@ -141,6 +138,13 @@ module NewRelic
|
|
141
138
|
:url => "https://rubygems.org/gems/sequel",
|
142
139
|
:feed => "https://rubygems.org/gems/sequel/versions.atom"
|
143
140
|
},
|
141
|
+
:mongo =>
|
142
|
+
{
|
143
|
+
:type => :database,
|
144
|
+
:supported => ["~>1.8.0", "~>1.9.0"],
|
145
|
+
:url => "https://rubygems.org/gems/mongo",
|
146
|
+
:feed => "https://rubygems.org/gems/mongo/versions.atom"
|
147
|
+
},
|
144
148
|
|
145
149
|
# Background Jobs
|
146
150
|
:resque =>
|
@@ -226,6 +226,10 @@ module NewRelic
|
|
226
226
|
notice_extra_data(key, duration, :key)
|
227
227
|
end
|
228
228
|
|
229
|
+
def notice_nosql_statement(statement, duration)
|
230
|
+
notice_extra_data(statement, duration, :statement)
|
231
|
+
end
|
232
|
+
|
229
233
|
# Set parameters on the current segment.
|
230
234
|
def add_segment_parameters( params )
|
231
235
|
return unless builder
|
data/lib/new_relic/version.rb
CHANGED
data/lib/tasks/versions.rake
CHANGED
@@ -33,7 +33,7 @@ namespace :newrelic do
|
|
33
33
|
def write_versions(title, type, erb, suppress_versions = false)
|
34
34
|
anchor = title.downcase.gsub(" ", "_")
|
35
35
|
versions = versions_for_type(type)
|
36
|
-
puts erb.result(binding)
|
36
|
+
puts erb.result(binding).gsub(/^ *$/, '')
|
37
37
|
end
|
38
38
|
|
39
39
|
VersionStruct = Struct.new(:name, :supported, :deprecated, :experimental, :notes)
|
data/test/agent_helper.rb
CHANGED
@@ -205,6 +205,10 @@ unless defined?( assert_false )
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
+
unless defined? ( refute )
|
209
|
+
alias refute assert_false
|
210
|
+
end
|
211
|
+
|
208
212
|
# Mock up a transaction for testing purposes, optionally specifying a name and
|
209
213
|
# transaction type. The given block will be executed within the context of the
|
210
214
|
# dummy transaction.
|
@@ -14,7 +14,7 @@ platforms :jruby do
|
|
14
14
|
gem "jruby-openssl"
|
15
15
|
end
|
16
16
|
|
17
|
-
platforms :
|
17
|
+
platforms :ruby do
|
18
18
|
gem "mysql"
|
19
19
|
gem "sqlite3-ruby"
|
20
20
|
gem "sqlite3"
|
@@ -22,6 +22,10 @@ end
|
|
22
22
|
|
23
23
|
platforms :rbx do
|
24
24
|
gem "rubysl"
|
25
|
+
gem "rubysl-json"
|
26
|
+
# If we don't skip the require here, test-unit tries to install its at_exit
|
27
|
+
# hook and run when we run our rake task to create the test DB.
|
28
|
+
gem "rubysl-test-unit", :require => false
|
25
29
|
gem "racc" # https://github.com/rubinius/rubinius/issues/2632
|
26
30
|
end
|
27
31
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
## flaky_proxy
|
2
|
+
|
3
|
+
`flaky_proxy` helps you simulate failures in an HTTP service in a configurable
|
4
|
+
way, without modifying the underlying service.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
```
|
9
|
+
flaky_proxy -l 8888 -t 8081 rules
|
10
|
+
```
|
11
|
+
|
12
|
+
Where `rules` is a file with the following content:
|
13
|
+
|
14
|
+
```
|
15
|
+
match /foo/ { close }
|
16
|
+
|
17
|
+
match /bar/ do
|
18
|
+
close
|
19
|
+
pass
|
20
|
+
end
|
21
|
+
|
22
|
+
match /baz/ do
|
23
|
+
respond :status => 503
|
24
|
+
respond :body => '{ "error": "bad things happened" }'
|
25
|
+
pass
|
26
|
+
end
|
27
|
+
|
28
|
+
match /slowdown/ do
|
29
|
+
delay 10
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
This will instruct `flaky_proxy` to listen for incoming connections on port
|
34
|
+
8888, and forward HTTP requests recieved on this port on to the server running
|
35
|
+
on localhost on port 8081.
|
36
|
+
|
37
|
+
Incoming requests will be evaluated against the match rules specified in the
|
38
|
+
`rules` file that you pass to `flaky_proxy`. Each call to `match` takes a Regexp
|
39
|
+
and a block.
|
40
|
+
|
41
|
+
The Regexp is evaluated against the URL on the incoming request to
|
42
|
+
determine whether the rule matches a given request. Each request will be handled
|
43
|
+
by the *first* matching rule (or the default rule if no matches are found).
|
44
|
+
|
45
|
+
The block passed to `match` should contain a sequence of *actions* for handling
|
46
|
+
matching requests. Actions will be applied in sequence (the first matching
|
47
|
+
request will get the first action, the second will get the second, and so on).
|
48
|
+
Once all of the actions have been evaluated, the final action in the block will
|
49
|
+
continue to be used.
|
50
|
+
|
51
|
+
The `rules` file will be watched for changes automatically, and the rules will
|
52
|
+
be potentially reloaded each time the proxy accepts a new connection.
|
53
|
+
|
54
|
+
If the `rules` file is omitted, the all requests will be transparently proxied to the backend server.
|
55
|
+
|
56
|
+
### Available Actions
|
57
|
+
|
58
|
+
#### pass
|
59
|
+
|
60
|
+
Pass the request on to the backend server without modification.
|
61
|
+
|
62
|
+
#### close
|
63
|
+
|
64
|
+
Close the TCP connection from the client before forwarding it on to the backend server.
|
65
|
+
|
66
|
+
#### respond(response_spec)
|
67
|
+
|
68
|
+
Respond to the client with a canned response, instead of forwarding the request on to the backend server. `response_spec` should be a `Hash` describing the canned response to be sent to the client. Recognized keys in the `response_spec` are:
|
69
|
+
|
70
|
+
* `:status` - A `Fixnum` with the HTTP status code. Default: 200.
|
71
|
+
* `:headers` - A `Hash` with response headers. Default: the `Content-Length` header will be automatically set based on the response body length.
|
72
|
+
* `:body` - A `String` containing the HTTP response body. Default = `''`.
|
73
|
+
|
74
|
+
#### delay(amount)
|
75
|
+
|
76
|
+
Delay for `amount` seconds before forwarding the request on to the backend server.
|
77
|
+
|
78
|
+
## Caveats
|
79
|
+
|
80
|
+
* Totally single-threaded and non-evented, therefore cannot handle multiple client connections at once.
|
81
|
+
* Errors introduced in the rules file will likely the process to crash instead of just printing an error.
|
82
|
+
* Almost certainly doesn't handle string encodings correctly
|