Skip to content

Commit

Permalink
Merge pull request #1544 from ruby-agent/dev
Browse files Browse the repository at this point in the history
4.2.0 RC 1
  • Loading branch information
Chris Pine committed May 18, 2017
2 parents 43ec214 + b44111f commit 110fe19
Show file tree
Hide file tree
Showing 83 changed files with 1,061 additions and 1,470 deletions.
55 changes: 30 additions & 25 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ notifications:

rvm:
# Run slowest builds first to try and optimize overall cycle time.
- jruby-9.1.2.0
- 2.4.0
- 2.3.3
- 2.2.6
- jruby-9.1.8.0
- 2.4.1
- 2.3.4
- 2.2.7
- 2.1.10
- 2.0.0-p648

Expand All @@ -61,6 +61,7 @@ env:
- TYPE=UNIT ENVIRONMENT=rails41
- TYPE=UNIT ENVIRONMENT=rails42
- TYPE=UNIT ENVIRONMENT=rails50
- TYPE=UNIT ENVIRONMENT=rails51
- TYPE=UNIT ENVIRONMENT=norails
- TYPE=FUNCTIONAL GROUP=agent
- TYPE=FUNCTIONAL GROUP=api
Expand All @@ -79,39 +80,39 @@ matrix:
exclude:
# Unsupported Rails/Ruby combinations
# 2.4
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails21
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails22
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails23
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails30
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails31
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails32
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails40
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails41
- rvm: 2.4.0
- rvm: 2.4.1
env: TYPE=UNIT ENVIRONMENT=rails42

# 2.3
- rvm: 2.3.3
- rvm: 2.3.4
env: TYPE=UNIT ENVIRONMENT=rails21
- rvm: 2.3.3
- rvm: 2.3.4
env: TYPE=UNIT ENVIRONMENT=rails22
- rvm: 2.3.3
- rvm: 2.3.4
env: TYPE=UNIT ENVIRONMENT=rails23

# 2.2
- rvm: 2.2.6
- rvm: 2.2.7
env: TYPE=UNIT ENVIRONMENT=rails21
- rvm: 2.2.6
- rvm: 2.2.7
env: TYPE=UNIT ENVIRONMENT=rails22
- rvm: 2.2.6
- rvm: 2.2.7
env: TYPE=UNIT ENVIRONMENT=rails23

# 2.1
Expand All @@ -123,6 +124,8 @@ matrix:
env: TYPE=UNIT ENVIRONMENT=rails23
- rvm: 2.1.10
env: TYPE=UNIT ENVIRONMENT=rails50
- rvm: 2.1.10
env: TYPE=UNIT ENVIRONMENT=rails51

# 2.0
- rvm: 2.0.0-p648
Expand All @@ -133,17 +136,19 @@ matrix:
env: TYPE=UNIT ENVIRONMENT=rails23
- rvm: 2.0.0-p648
env: TYPE=UNIT ENVIRONMENT=rails50
- rvm: 2.0.0-p648
env: TYPE=UNIT ENVIRONMENT=rails51

# jruby 9.0
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails21
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails22
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails23
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails30
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails31
- rvm: jruby-9.1.2.0
- rvm: jruby-9.1.8.0
env: TYPE=UNIT ENVIRONMENT=rails32
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# New Relic Ruby Agent Release Notes #

## v4.2.0 ##

* Sinatra 2.0 and Padrino 0.14.x Support

The agent has been verified against the latest versions of Sinatra and Padrino.

* Rails 5.1 Support

The Ruby agent has been validated against the latest release of Ruby on Rails!

* APP_ENV considered when determining environment

The agent will now consider the APP_ENV environment when starting up.

* Test files excluded from gem

The gemspec has been updated to exclude test files from being packaged into the
gem. Thanks dimko for the contribution!

## v4.1.0 ##

* Developer Mode removed
Expand Down
12 changes: 9 additions & 3 deletions lib/new_relic/agent/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module NewRelic
module Agent
module Database
MAX_QUERY_LENGTH = 16384
ELLIPSIS = "...".freeze

extend self

Expand All @@ -42,7 +43,7 @@ def capture_query(query)

def truncate_query(query)
if query.length > (MAX_QUERY_LENGTH - 4)
query[0..MAX_QUERY_LENGTH - 4] + '...'
query[0..MAX_QUERY_LENGTH - 4] << ELLIPSIS
else
query
end
Expand Down Expand Up @@ -221,6 +222,13 @@ def explain
end
end

NEWLINE = "\n".freeze

def append_sql new_sql
return if new_sql.empty?
@sql = Database.truncate_query(@sql << NEWLINE << new_sql)
end

private

POSTGRES_PREFIX = 'postgres'.freeze
Expand All @@ -244,8 +252,6 @@ def symbolized_adapter(adapter)
end
end

ELLIPSIS = "...".freeze

def explainable?
return false unless @explainer && is_select?(@sql)

Expand Down
15 changes: 8 additions & 7 deletions lib/new_relic/agent/datastores.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ def self.wrap(product, operation, collection = nil, callback = nil)
# @api public
#
def self.notice_sql(query, scoped_metric, elapsed)
agent = NewRelic::Agent.instance
agent.transaction_sampler.notice_sql(query, nil, elapsed)
agent.sql_sampler.notice_sql(query, scoped_metric, nil, elapsed)
state = TransactionState.tl_get
if (txn = state.current_transaction) && (segment = txn.current_segment) && segment.respond_to?(:notice_sql)
segment.notice_sql(query)
end
nil
end

Expand Down Expand Up @@ -179,10 +180,10 @@ def self.notice_sql(query, scoped_metric, elapsed)
def self.notice_statement(statement, elapsed)
# Settings may change eventually, but for now we follow the same
# capture rules as SQL for non-SQL statements.
return unless NewRelic::Agent::Database.should_record_sql?

agent = NewRelic::Agent.instance
agent.transaction_sampler.notice_nosql_statement(statement, elapsed)
state = TransactionState.tl_get
if (txn = state.current_transaction) && (segment = txn.current_segment) && segment.respond_to?(:notice_nosql_statement)
segment.notice_nosql_statement(statement)
end
nil
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,12 @@ def start_transaction(event)
:request => event.request,
:filtered_params => filter(event.payload[:params]),
:apdex_start_time => event.queue_start,
:transaction_name => event.metric_name)
:transaction_name => event.metric_name,
:ignore_apdex => event.apdex_ignored?,
:ignore_enduser => event.enduser_ignored?)
end

def stop_transaction(event)
txn = state.current_transaction
txn.ignore_apdex! if event.apdex_ignored?
txn.ignore_enduser! if event.enduser_ignored?
Transaction.stop(state)
end

Expand Down
30 changes: 26 additions & 4 deletions lib/new_relic/agent/instrumentation/active_record_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,36 @@ class ActiveRecordSubscriber < EventedSubscriber
CACHED_QUERY_NAME = 'CACHE'.freeze

def initialize
define_cachedp_method
# We cache this in an instance variable to avoid re-calling method
# on each query.
@explainer = method(:get_explain_plan)
super
end

# The cached? method is dynamically defined based on ActiveRecord version.
# This file can and often is required before ActiveRecord is loaded. For
# that reason we define the cache? method in initialize. The behavior
# difference is that AR 5.1 includes a key in the payload to check,
# where older versions set the :name to CACHE.

def define_cachedp_method
# we don't expect this to be called more than once, but we're being
# defensive.
return if defined?(cached?)
if ::ActiveRecord::VERSION::STRING >= "5.1.0"
def cached?(payload)
payload.fetch(:cached, false)
end
else
def cached?(payload)
payload[:name] == CACHED_QUERY_NAME
end
end
end

def start(name, id, payload) #THREAD_LOCAL_ACCESS
return if payload[:name] == CACHED_QUERY_NAME
return if cached?(payload)
return unless NewRelic::Agent.tl_is_execution_traced?
config = active_record_config(payload)
event = ActiveRecordEvent.new(name, Time.now, nil, id, payload, @explainer, config)
Expand All @@ -31,7 +53,7 @@ def start(name, id, payload) #THREAD_LOCAL_ACCESS
end

def finish(name, id, payload) #THREAD_LOCAL_ACCESS
return if payload[:name] == CACHED_QUERY_NAME
return if cached?(payload)
return unless state.is_execution_traced?
event = pop_event(id)
event.finish
Expand Down Expand Up @@ -109,8 +131,8 @@ def start_segment
# See comment for start_segment as we continue to work around limitations of the
# current tracer in this method.
def finish
if state.current_transaction
state.traced_method_stack.push_segment state, @segment
if txn = state.current_transaction
txn.add_segment @segment
end
@segment.finish
end
Expand Down
6 changes: 4 additions & 2 deletions lib/new_relic/agent/instrumentation/acts_as_solr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.

require 'new_relic/agent/database'

module NewRelic
module Instrumentation
module ActsAsSolrInstrumentation
module ParserMethodsInstrumentation
def parse_query_with_newrelic(*args)
self.class.trace_execution_scoped(["SolrClient/ActsAsSolr/query"]) do
t0 = Time.now
begin
parse_query_without_newrelic(*args)
ensure
NewRelic::Agent.instance.transaction_sampler.notice_nosql(args.first.inspect, (Time.now - t0).to_f) rescue nil
return unless txn = ::NewRelic::Agent::TransactionState.tl_get.current_transaction
txn.current_segment.params[:statement] = ::NewRelic::Agent::Database.truncate_query(args.first.inspect) rescue nil
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def perform_action_with_newrelic_trace(*args, &block) #THREAD_LOCAL_ACCESS
txn_options = create_transaction_options(trace_options, category, state)

begin
txn = Transaction.start(state, category, txn_options)
Transaction.start(state, category, txn_options)

begin
yield
Expand All @@ -366,10 +366,6 @@ def perform_action_with_newrelic_trace(*args, &block) #THREAD_LOCAL_ACCESS
end

ensure
if txn
txn.ignore_apdex! if ignore_apdex?
txn.ignore_enduser! if ignore_enduser?
end
Transaction.stop(state)
end
end
Expand Down Expand Up @@ -430,6 +426,8 @@ def create_transaction_options(trace_options, category, state)
txn_options[:filtered_params] = trace_options[:params]
txn_options[:transaction_name] = TransactionNamer.name_for(nil, self, category, trace_options)
txn_options[:apdex_start_time] = detect_queue_start_time(state)
txn_options[:ignore_apdex] = ignore_apdex?
txn_options[:ignore_enduser] = ignore_enduser?
txn_options
end

Expand Down
7 changes: 5 additions & 2 deletions lib/new_relic/agent/instrumentation/data_mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,11 @@ def log(msg) #THREAD_LOCAL_ACCESS
state = NewRelic::Agent::TransactionState.tl_get
return unless state.is_execution_traced?

duration = msg.duration / 1000000.0
NewRelic::Agent.instance.transaction_sampler.notice_sql(msg.query, nil, duration, state)
txn = state.current_transaction

if txn && txn.current_segment.respond_to?(:notice_sql)
txn.current_segment.notice_sql msg.query
end
ensure
super
end
Expand Down
10 changes: 5 additions & 5 deletions lib/new_relic/agent/instrumentation/mongo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ def hook_instrument_method(target_class)

# It's key that this method eats all exceptions, as it rests between the
# Mongo operation the user called and us returning them the data. Be safe!
def new_relic_notice_statement(t0, payload, name)
def new_relic_notice_statement(segment, payload, name)
statement = NewRelic::Agent::Datastores::Mongo::StatementFormatter.format(payload, name)
if statement
NewRelic::Agent.instance.transaction_sampler.notice_nosql_statement(statement, (Time.now - t0).to_f)
segment.notice_nosql_statement statement
end
rescue => e
NewRelic::Agent.logger.debug("Exception during Mongo statement gathering", e)
Expand All @@ -85,7 +85,7 @@ def instrument_with_new_relic_trace(name, payload = {}, &block)
instrument_without_new_relic_trace(name, payload, &block)
end

new_relic_notice_statement(segment.start_time, payload, name) if segment
new_relic_notice_statement(segment, payload, name) if segment
result
ensure
segment.finish if segment
Expand All @@ -107,7 +107,7 @@ def save_with_new_relic_trace(doc, opts = {}, &block)
save_without_new_relic_trace(doc, opts, &block)
end

new_relic_notice_statement(segment.start_time, doc, :save) if segment
new_relic_notice_statement(segment, doc, :save) if segment
result
ensure
segment.finish if segment
Expand Down Expand Up @@ -138,7 +138,7 @@ def ensure_index_with_new_relic_trace(spec, opts = {}, &block)
spec.dup
end

new_relic_notice_statement(segment.start_time, spec, :ensureIndex) if segment
new_relic_notice_statement(segment, spec, :ensureIndex) if segment
result
ensure
segment.finish if segment
Expand Down
4 changes: 3 additions & 1 deletion lib/new_relic/agent/instrumentation/rake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ def self.instrument_invoke_prerequisites_concurrently(task)
def invoke_prerequisites_concurrently(*_)
NewRelic::Agent::MethodTracer.trace_execution_scoped("Rake/execute/multitask") do
prereqs = self.prerequisite_tasks.map(&:name).join(", ")
NewRelic::Agent::Datastores.notice_statement("Couldn't trace concurrent prereq tasks: #{prereqs}", 0)
if txn = ::NewRelic::Agent::TransactionState.tl_get.current_transaction
txn.current_segment.params[:statement] = NewRelic::Agent::Database.truncate_query("Couldn't trace concurrent prereq tasks: #{prereqs}")
end
super
end
end
Expand Down

0 comments on commit 110fe19

Please sign in to comment.