newrelic/rpm_contrib — pull request #34 by raphaelcm (2013-02-07 19:34:26+00:00)
Title: Fix unexpected nil error with Mongo

This pull request fixes the following bug:

`ruby 1.8.7`
`rails 3.0.20`
`mongo 1.4.0`
`rpm_contrib 2.1.11`

```ruby
> conn = Mongo::Connection.new("localhost")
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
from /var/bundler/turtle/ruby/1.8/gems/rpm_contrib-2.1.11/lib/rpm_contrib/instrumentation/mongo.rb:18:in `instrument'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/cursor.rb:463:in `send_initial_query'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/cursor.rb:454:in `refresh'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/cursor.rb:124:in `next_document'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/db.rb:505:in `command'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/connection.rb:732:in `check_is_master'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/connection.rb:513:in `connect'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/connection.rb:688:in `setup'
from /var/bundler/turtle/ruby/1.8/gems/mongo-1.4.0/lib/../lib/mongo/connection.rb:104:in `initialize'
```

This happens because the `send_initial_query` method in the mongo gem (at least [version 1.4.0](https://github.com/mongodb/mongo-ruby-driver/blob/1.4.0/lib/mongo/cursor.rb#L460)) passes the `payload` object to the `instrument` method, **even if it is nil**.

```ruby
def send_initial_query
message = construct_query_message
payload = instrument_payload if @logger
instrument(:find, payload) do
results, @n_received, @cursor_id = @connection.receive_message(
Mongo::Constants::OP_QUERY, message, nil, @socket, @command,
@read_preference, @options & OP_QUERY_EXHAUST != 0)
@returned += @n_received
@cache += results
@query_run = true
close_cursor_if_query_complete
end
end
```

The `instrument_with_newrelic_trace` [method](https://github.com/newrelic/rpm_contrib/blob/master/lib/rpm_contrib/instrumentation/mongo.rb#L17) sets a default value for the parameter, but that only applies if the parameter is missing from the method call. If `nil` is passed in explicitly, then `payload` will remain `nil`, causing the exception when `payload[:collection]` is attempted.

```ruby
def instrument_with_newrelic_trace(name, payload = {}, &blk)
collection = payload[:collection]
if collection == '$cmd'
f = payload[:selector].first
name, collection = f if f
end

trace_execution_scoped("Database/#{collection}/#{name}") do
t0 = Time.now
res = instrument_without_newrelic_trace(name, payload, &blk)
NewRelic::Agent.instance.transaction_sampler.notice_sql(payload.inspect, nil, (Time.now - t0).to_f)
res
end
end
```

This pull request adds a line to explicitly set `payload` to its default value (`{}`) if it is `nil`.