newrelic_rpm 3.11.2.286 → 3.12.0.288
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/.yardopts +2 -0
- data/CHANGELOG +39 -4
- data/README.md +4 -2
- data/lib/new_relic/agent.rb +229 -214
- data/lib/new_relic/agent/agent.rb +23 -12
- data/lib/new_relic/agent/attribute_filter.rb +242 -0
- data/lib/new_relic/agent/attribute_processing.rb +62 -0
- data/lib/new_relic/agent/commands/xray_session_collection.rb +4 -1
- data/lib/new_relic/agent/configuration/default_source.rb +284 -30
- data/lib/new_relic/agent/configuration/high_security_source.rb +0 -8
- data/lib/new_relic/agent/configuration/manager.rb +1 -1
- data/lib/new_relic/agent/configuration/server_source.rb +86 -31
- data/lib/new_relic/agent/configuration/yaml_source.rb +1 -1
- data/lib/new_relic/agent/cross_app_monitor.rb +8 -13
- data/lib/new_relic/agent/cross_app_tracing.rb +15 -15
- data/lib/new_relic/agent/custom_event_aggregator.rb +6 -2
- data/lib/new_relic/agent/database.rb +15 -2
- data/lib/new_relic/agent/datastores.rb +52 -38
- data/lib/new_relic/agent/datastores/metric_helper.rb +2 -1
- data/lib/new_relic/agent/encoding_normalizer.rb +82 -0
- data/lib/new_relic/agent/error_collector.rb +125 -169
- data/lib/new_relic/agent/hash_extensions.rb +26 -0
- data/lib/new_relic/agent/http_clients/excon_wrappers.rb +13 -11
- data/lib/new_relic/agent/http_clients/uri_util.rb +9 -0
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -3
- data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +12 -5
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +6 -7
- data/lib/new_relic/agent/instrumentation/curb.rb +6 -6
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +4 -4
- data/lib/new_relic/agent/instrumentation/grape.rb +4 -3
- data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +6 -3
- data/lib/new_relic/agent/instrumentation/rails/errors.rb +9 -3
- data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +6 -1
- data/lib/new_relic/agent/instrumentation/rails3/errors.rb +9 -7
- data/lib/new_relic/agent/instrumentation/rails4/errors.rb +8 -6
- data/lib/new_relic/agent/instrumentation/resque.rb +2 -3
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +3 -3
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +2 -2
- data/lib/new_relic/agent/javascript_instrumentor.rb +24 -16
- data/lib/new_relic/agent/parameter_filtering.rb +8 -1
- data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +2 -2
- data/lib/new_relic/agent/sql_sampler.rb +1 -0
- data/lib/new_relic/agent/stats.rb +0 -4
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +5 -3
- data/lib/new_relic/agent/stats_engine/stats_hash.rb +4 -0
- data/lib/new_relic/agent/supported_versions.rb +2 -2
- data/lib/new_relic/agent/traced_method_stack.rb +3 -3
- data/lib/new_relic/agent/transaction.rb +141 -118
- data/lib/new_relic/agent/transaction/attributes.rb +161 -0
- data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +4 -4
- data/lib/new_relic/agent/transaction/trace.rb +150 -0
- data/lib/new_relic/agent/transaction/trace_node.rb +190 -0
- data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +2 -2
- data/lib/new_relic/agent/transaction_event_aggregator.rb +23 -7
- data/lib/new_relic/agent/transaction_sample_builder.rb +37 -62
- data/lib/new_relic/agent/transaction_sampler.rb +29 -66
- data/lib/new_relic/cli/commands/install.rb +2 -2
- data/lib/new_relic/coerce.rb +15 -28
- data/lib/new_relic/json_wrapper.rb +14 -73
- data/lib/new_relic/noticed_error.rb +81 -5
- data/lib/new_relic/rack/browser_monitoring.rb +14 -19
- data/lib/new_relic/rack/developer_mode.rb +68 -14
- data/lib/new_relic/rack/developer_mode/segment_summary.rb +56 -0
- data/lib/new_relic/version.rb +2 -2
- data/newrelic.yml +19 -196
- data/test/agent_helper.rb +42 -36
- data/test/config/newrelic.yml +0 -1
- data/test/environments/rails40/Gemfile +1 -1
- data/test/environments/rails41/Gemfile +1 -1
- data/test/environments/rails42/Gemfile +1 -1
- data/test/fixtures/cross_agent_tests/attribute_configuration.json +35 -0
- data/test/fixtures/cross_agent_tests/sql_obfuscation/README.md +19 -12
- data/test/fixtures/cross_agent_tests/sql_obfuscation/sql_obfuscation.json +365 -0
- data/test/multiverse/lib/multiverse/suite.rb +5 -1
- data/test/multiverse/suites/active_record/active_record_test.rb +8 -8
- data/test/multiverse/suites/agent_only/agent_attributes_test.rb +145 -0
- data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +8 -0
- data/test/multiverse/suites/agent_only/custom_queue_time_test.rb +5 -1
- data/test/multiverse/suites/agent_only/encoding_handling_test.rb +6 -6
- data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +2 -3
- data/test/multiverse/suites/agent_only/synthetics_test.rb +3 -3
- data/test/multiverse/suites/agent_only/testing_app.rb +4 -0
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +1 -1
- data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +9 -7
- data/test/multiverse/suites/curb/Envfile +5 -6
- data/test/multiverse/suites/curb/curb_test.rb +4 -5
- data/test/multiverse/suites/datamapper/datamapper_test.rb +2 -2
- data/test/multiverse/suites/excon/Envfile +11 -4
- data/test/multiverse/suites/excon/excon_test.rb +5 -5
- data/test/multiverse/suites/grape/config/newrelic.yml +1 -0
- data/test/multiverse/suites/grape/grape_test.rb +76 -12
- data/test/multiverse/suites/grape/grape_test_api.rb +16 -0
- data/test/multiverse/suites/high_security/config/newrelic.yml +43 -3
- data/test/multiverse/suites/high_security/high_security_test.rb +165 -9
- data/test/multiverse/suites/httpclient/Envfile +5 -1
- data/test/multiverse/suites/httpclient/httpclient_test.rb +2 -2
- data/test/multiverse/suites/memcached/Envfile +1 -1
- data/test/multiverse/suites/mongo/Envfile +8 -1
- data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +29 -29
- data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +43 -8
- data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +13 -3
- data/test/multiverse/suites/rails/Envfile +3 -3
- data/test/multiverse/suites/rails/error_tracing_test.rb +52 -31
- data/test/multiverse/suites/rails/gc_instrumentation_test.rb +1 -1
- data/test/multiverse/suites/rails/ignore_test.rb +1 -1
- data/test/multiverse/suites/rails/parameter_capture_test.rb +108 -40
- data/test/multiverse/suites/rails/request_statistics_test.rb +10 -4
- data/test/multiverse/suites/rails/view_instrumentation_test.rb +24 -24
- data/test/multiverse/suites/resque/instrumentation_test.rb +46 -12
- data/test/multiverse/suites/sequel/sequel_extension_test.rb +8 -8
- data/test/multiverse/suites/sequel/sequel_helpers.rb +11 -11
- data/test/multiverse/suites/sequel/sequel_plugin_test.rb +11 -11
- data/test/multiverse/suites/sidekiq/Envfile +1 -4
- data/test/multiverse/suites/sidekiq/after_suite.rb +9 -0
- data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +49 -16
- data/test/multiverse/suites/sidekiq/test_worker.rb +1 -2
- data/test/multiverse/suites/sinatra/Envfile +1 -1
- data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -0
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +0 -4
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +0 -4
- data/test/multiverse/suites/sinatra/sinatra_parameter_capture_test.rb +65 -0
- data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +0 -11
- data/test/multiverse/suites/typhoeus/Envfile +8 -2
- data/test/multiverse/suites/typhoeus/typhoeus_test.rb +4 -4
- data/test/new_relic/agent/agent/connect_test.rb +13 -9
- data/test/new_relic/agent/agent_test.rb +34 -24
- data/test/new_relic/agent/attribute_filter_test.rb +218 -0
- data/test/new_relic/agent/attribute_processing_test.rb +160 -0
- data/test/new_relic/agent/configuration/default_source_test.rb +88 -0
- data/test/new_relic/agent/configuration/manager_test.rb +3 -4
- data/test/new_relic/agent/configuration/orphan_configuration_test.rb +3 -1
- data/test/new_relic/agent/configuration/server_source_test.rb +39 -0
- data/test/new_relic/agent/cross_app_monitor_test.rb +6 -30
- data/test/new_relic/agent/cross_app_tracing_test.rb +12 -12
- data/test/new_relic/agent/database/sql_obfuscation_test.rb +39 -65
- data/test/new_relic/agent/datastores/metric_helper_test.rb +36 -0
- data/test/new_relic/agent/encoding_normalizer_test.rb +66 -0
- data/test/new_relic/agent/error_collector_test.rb +181 -34
- data/test/new_relic/agent/hash_extensions_test.rb +34 -0
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +20 -23
- data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +12 -12
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +5 -5
- data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +4 -4
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +21 -11
- data/test/new_relic/agent/javascript_instrumentor_test.rb +69 -45
- data/test/new_relic/agent/pipe_service_test.rb +2 -2
- data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +1 -1
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +8 -7
- data/test/new_relic/agent/stats_engine/stats_hash_test.rb +2 -2
- data/test/new_relic/agent/threading/backtrace_node_test.rb +2 -2
- data/test/new_relic/agent/transaction/attributes_test.rb +276 -0
- data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +10 -10
- data/test/new_relic/agent/transaction/trace_node_test.rb +361 -0
- data/test/new_relic/agent/transaction/trace_test.rb +394 -0
- data/test/new_relic/agent/transaction/xray_sample_buffer_test.rb +1 -1
- data/test/new_relic/agent/transaction_event_aggregator_test.rb +127 -57
- data/test/new_relic/agent/transaction_sample_builder_test.rb +70 -78
- data/test/new_relic/agent/transaction_sampler_test.rb +76 -185
- data/test/new_relic/agent/transaction_test.rb +283 -135
- data/test/new_relic/agent_test.rb +27 -12
- data/test/new_relic/cli/commands/install_test.rb +27 -0
- data/test/new_relic/coerce_test.rb +0 -59
- data/test/new_relic/data_container_tests.rb +5 -5
- data/test/new_relic/fake_collector.rb +27 -9
- data/test/new_relic/filtering_test_app.rb +2 -1
- data/test/new_relic/http_client_test_cases.rb +16 -16
- data/test/new_relic/json_wrapper_test.rb +0 -54
- data/test/new_relic/marshalling_test_cases.rb +1 -0
- data/test/new_relic/multiverse_helpers.rb +144 -0
- data/test/new_relic/noticed_error_test.rb +112 -9
- data/test/new_relic/rack/browser_monitoring_test.rb +12 -7
- data/test/new_relic/{transaction_analysis → rack/developer_mode}/segment_summary_test.rb +5 -4
- data/test/new_relic/rack/developer_mode_test.rb +17 -3
- data/test/new_relic/rack/error_collector_test.rb +1 -1
- data/test/performance/lib/performance/instrumentation/stackprof.rb +1 -1
- data/test/performance/script/runner +2 -2
- data/test/performance/suites/active_record.rb +3 -3
- data/test/performance/suites/agent_attributes.rb +62 -0
- data/test/performance/suites/rack_middleware.rb +78 -28
- data/test/performance/suites/transaction_tracing.rb +35 -0
- data/test/test_helper.rb +9 -1
- data/ui/helpers/developer_mode_helper.rb +16 -23
- data/ui/views/newrelic/_sample.rhtml +3 -3
- data/ui/views/newrelic/_segment.rhtml +1 -1
- data/ui/views/newrelic/_show_sample_summary.rhtml +1 -1
- data/ui/views/newrelic/show_sample.rhtml +5 -4
- metadata +23 -80
- data/lib/new_relic/agent/transaction/force_persist_sample_buffer.rb +0 -25
- data/lib/new_relic/transaction_analysis.rb +0 -80
- data/lib/new_relic/transaction_analysis/segment_summary.rb +0 -53
- data/lib/new_relic/transaction_sample.rb +0 -207
- data/lib/new_relic/transaction_sample/composite_segment.rb +0 -31
- data/lib/new_relic/transaction_sample/fake_segment.rb +0 -13
- data/lib/new_relic/transaction_sample/segment.rb +0 -197
- data/lib/new_relic/transaction_sample/summary_segment.rb +0 -25
- data/lib/new_relic/url_rule.rb +0 -18
- data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.obfuscated +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.sql +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.obfuscated +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.sql +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.sql +0 -4
- data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_double_quoted_string.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_single_quoted_string.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/README.md +0 -4
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/end_of_line_comments_with_quotes.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/end_of_line_comments_with_quotes.sql +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_comments_and_quotes.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_comments_and_quotes.sql +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_comments_and_newlines.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_comments_and_newlines.sql +0 -4
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_end_of_line_comments.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_end_of_line_comments.sql +0 -3
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/quote_delimiters_in_comments.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/quote_delimiters_in_comments.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.sql +0 -4
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.sql +0 -2
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.sql +0 -4
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.sql +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.obfuscated +0 -1
- data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.sql +0 -1
- data/test/new_relic/agent/error_collector/notice_error_test.rb +0 -261
- data/test/new_relic/agent/transaction/force_persist_sample_buffer_test.rb +0 -52
- data/test/new_relic/transaction_analysis_test.rb +0 -125
- data/test/new_relic/transaction_sample/composite_segment_test.rb +0 -38
- data/test/new_relic/transaction_sample/fake_segment_test.rb +0 -18
- data/test/new_relic/transaction_sample/segment_test.rb +0 -361
- data/test/new_relic/transaction_sample/summary_segment_test.rb +0 -34
- data/test/new_relic/transaction_sample_subtest_test.rb +0 -41
- data/test/new_relic/transaction_sample_test.rb +0 -361
@@ -32,9 +32,9 @@ class NewRelic::Cli::Install < NewRelic::Cli::Command
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
@license_key ||= NO_LICENSE_KEY
|
35
|
-
@app_name ||= @leftover
|
35
|
+
@app_name ||= @leftover.join(" ")
|
36
|
+
@agent_version = NewRelic::VERSION::STRING
|
36
37
|
raise CommandFailure.new("Application name required.", @options) unless @app_name && @app_name.size > 0
|
37
|
-
@generated_for_user ||= @user_string || ""
|
38
38
|
end
|
39
39
|
|
40
40
|
def run
|
data/lib/new_relic/coerce.rb
CHANGED
@@ -10,6 +10,8 @@ module NewRelic
|
|
10
10
|
# to provide documentation of expected types on to_collector_array methods,
|
11
11
|
# and to log failures if totally invalid data gets into outgoing data
|
12
12
|
module Coerce
|
13
|
+
module_function
|
14
|
+
|
13
15
|
def int(value, context=nil)
|
14
16
|
Integer(value)
|
15
17
|
rescue => error
|
@@ -42,36 +44,21 @@ module NewRelic
|
|
42
44
|
""
|
43
45
|
end
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
unless value.is_a? Hash
|
55
|
-
raise ArgumentError, "Expected Hash but got #{value.class}"
|
56
|
-
end
|
57
|
-
value.inject({}) do |memo, (key, val)|
|
58
|
-
case val
|
59
|
-
when String, Integer, TrueClass, FalseClass
|
60
|
-
memo[key.to_s] = val
|
61
|
-
when Float
|
62
|
-
if val.finite?
|
63
|
-
memo[key.to_s] = val
|
64
|
-
else
|
65
|
-
memo[key.to_s] = nil
|
66
|
-
end
|
67
|
-
when Symbol
|
68
|
-
memo[key.to_s] = val.to_s
|
47
|
+
def scalar(val)
|
48
|
+
case val
|
49
|
+
when String, Integer, TrueClass, FalseClass
|
50
|
+
val
|
51
|
+
when Float
|
52
|
+
if val.finite?
|
53
|
+
val
|
54
|
+
else
|
55
|
+
nil
|
69
56
|
end
|
70
|
-
|
57
|
+
when Symbol
|
58
|
+
val.to_s
|
59
|
+
else
|
60
|
+
"#<#{val.class.to_s}>"
|
71
61
|
end
|
72
|
-
rescue => error
|
73
|
-
log_failure(value.class, 'valid event params', context, error)
|
74
|
-
{}
|
75
62
|
end
|
76
63
|
|
77
64
|
def log_failure(value, type, context, error)
|
@@ -2,6 +2,9 @@
|
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
|
+
require 'new_relic/agent/encoding_normalizer'
|
6
|
+
require 'new_relic/agent/hash_extensions'
|
7
|
+
|
5
8
|
module NewRelic
|
6
9
|
class JSONWrapper
|
7
10
|
def self.load_native_json
|
@@ -26,7 +29,7 @@ module NewRelic
|
|
26
29
|
@load_method = ::JSON.method(:load)
|
27
30
|
@backend_name = :json
|
28
31
|
return true
|
29
|
-
rescue StandardError, ScriptError
|
32
|
+
rescue StandardError, ScriptError => err
|
30
33
|
NewRelic::Agent.logger.debug "%p while loading JSON library: %s" % [ err, err.message ] if
|
31
34
|
defined?( NewRelic::Agent ) && NewRelic::Agent.respond_to?( :logger )
|
32
35
|
end
|
@@ -49,89 +52,27 @@ module NewRelic
|
|
49
52
|
@backend_name
|
50
53
|
end
|
51
54
|
|
52
|
-
def self.normalize_string(s)
|
53
|
-
choose_normalizer unless @normalizer
|
54
|
-
@normalizer.normalize(s)
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.choose_normalizer
|
58
|
-
if NewRelic::LanguageSupport.supports_string_encodings?
|
59
|
-
@normalizer = EncodingNormalizer
|
60
|
-
else
|
61
|
-
@normalizer = IconvNormalizer
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class EncodingNormalizer
|
66
|
-
def self.normalize(s)
|
67
|
-
encoding = s.encoding
|
68
|
-
if (encoding == Encoding::UTF_8 || encoding == Encoding::ISO_8859_1) && s.valid_encoding?
|
69
|
-
return s
|
70
|
-
end
|
71
|
-
|
72
|
-
# If the encoding is not valid, or it's ASCII-8BIT, we know conversion to
|
73
|
-
# UTF-8 is likely to fail, so treat it as ISO-8859-1 (byte-preserving).
|
74
|
-
normalized = s.dup
|
75
|
-
if encoding == Encoding::ASCII_8BIT || !s.valid_encoding?
|
76
|
-
normalized.force_encoding(Encoding::ISO_8859_1)
|
77
|
-
else
|
78
|
-
# Encoding is valid and non-binary, so it might be cleanly convertible
|
79
|
-
# to UTF-8. Give it a try and fall back to ISO-8859-1 if it fails.
|
80
|
-
begin
|
81
|
-
normalized.encode!(Encoding::UTF_8)
|
82
|
-
rescue
|
83
|
-
normalized.force_encoding(Encoding::ISO_8859_1)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
normalized
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
class IconvNormalizer
|
91
|
-
def self.normalize(s)
|
92
|
-
if @iconv.nil?
|
93
|
-
require 'iconv'
|
94
|
-
@iconv = Iconv.new('utf-8', 'iso-8859-1')
|
95
|
-
end
|
96
|
-
@iconv.iconv(s)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.normalize(object)
|
101
|
-
case object
|
102
|
-
when String
|
103
|
-
normalize_string(object)
|
104
|
-
when Symbol
|
105
|
-
normalize_string(object.to_s)
|
106
|
-
when Array
|
107
|
-
return object if object.empty?
|
108
|
-
result = object.map { |x| normalize(x) }
|
109
|
-
result
|
110
|
-
when Hash
|
111
|
-
return object if object.empty?
|
112
|
-
hash = {}
|
113
|
-
object.each_pair do |k, v|
|
114
|
-
k = normalize_string(k) if k.is_a?(String)
|
115
|
-
k = normalize_string(k.to_s) if k.is_a?(Symbol)
|
116
|
-
hash[k] = normalize(v)
|
117
|
-
end
|
118
|
-
hash
|
119
|
-
else
|
120
|
-
object
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
55
|
def self.supports_normalization?
|
125
56
|
NewRelic::LanguageSupport.supports_string_encodings?
|
126
57
|
end
|
127
58
|
|
128
59
|
def self.dump(object, options={})
|
129
60
|
object = normalize(object) if options[:normalize]
|
61
|
+
# okjson doesn't handle symbol keys, so we must stringify them before encoding
|
62
|
+
object = Agent::HashExtensions.stringify_keys_in_object(object) if backend_name == :okjson
|
130
63
|
@dump_method.call(object)
|
131
64
|
end
|
132
65
|
|
133
66
|
def self.load(string)
|
134
67
|
@load_method.call(string)
|
135
68
|
end
|
69
|
+
|
70
|
+
def self.normalize_string(s)
|
71
|
+
NewRelic::Agent::StringNormalizer.normalize_string(s)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.normalize(o)
|
75
|
+
NewRelic::Agent::EncodingNormalizer.normalize_object(o)
|
76
|
+
end
|
136
77
|
end
|
137
78
|
end
|
@@ -3,20 +3,23 @@
|
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
5
|
require 'new_relic/helper'
|
6
|
+
require 'new_relic/agent/attribute_filter'
|
6
7
|
|
7
8
|
# This class encapsulates an error that was noticed by New Relic in a managed app.
|
8
9
|
class NewRelic::NoticedError
|
9
10
|
extend NewRelic::CollectionHelper
|
10
|
-
|
11
|
+
|
12
|
+
attr_accessor :path, :timestamp, :message, :exception_class_name,
|
13
|
+
:request_uri, :file_name, :line_number, :stack_trace,
|
14
|
+
:attributes_from_notice_error, :attributes
|
15
|
+
|
11
16
|
attr_reader :exception_id, :is_internal
|
12
17
|
|
13
18
|
STRIPPED_EXCEPTION_REPLACEMENT_MESSAGE = "Message removed by New Relic 'strip_exception_messages' setting"
|
14
19
|
|
15
|
-
def initialize(path,
|
20
|
+
def initialize(path, exception, timestamp = Time.now)
|
16
21
|
@exception_id = exception.object_id
|
17
22
|
@path = path
|
18
|
-
@params = NewRelic::NoticedError.normalize_params(data)
|
19
|
-
|
20
23
|
@exception_class_name = exception.is_a?(Exception) ? exception.class.name : 'Error'
|
21
24
|
|
22
25
|
# It's critical that we not hold onto the exception class constant in this
|
@@ -83,6 +86,79 @@ class NewRelic::NoticedError
|
|
83
86
|
string(path),
|
84
87
|
string(message),
|
85
88
|
string(exception_class_name),
|
86
|
-
|
89
|
+
build_params ]
|
90
|
+
end
|
91
|
+
|
92
|
+
USER_ATTRIBUTES = "userAttributes".freeze
|
93
|
+
AGENT_ATTRIBUTES = "agentAttributes".freeze
|
94
|
+
INTRINSIC_ATTRIBUTES = "intrinsics".freeze
|
95
|
+
|
96
|
+
EMPTY_HASH = {}.freeze
|
97
|
+
|
98
|
+
DESTINATION = NewRelic::Agent::AttributeFilter::DST_ERROR_COLLECTOR
|
99
|
+
|
100
|
+
def build_params
|
101
|
+
params = base_parameters
|
102
|
+
append_attributes(params, USER_ATTRIBUTES, merged_custom_attributes)
|
103
|
+
append_attributes(params, AGENT_ATTRIBUTES, build_agent_attributes)
|
104
|
+
append_attributes(params, INTRINSIC_ATTRIBUTES, build_intrinsic_attributes)
|
105
|
+
params
|
87
106
|
end
|
107
|
+
|
108
|
+
def base_parameters
|
109
|
+
params = {}
|
110
|
+
params[:request_uri] = request_uri if request_uri
|
111
|
+
params[:file_name] = file_name if file_name
|
112
|
+
params[:line_number] = line_number if line_number
|
113
|
+
params[:stack_trace] = stack_trace if stack_trace
|
114
|
+
params
|
115
|
+
end
|
116
|
+
|
117
|
+
# We can get custom attributes from two sources--the transaction, which we
|
118
|
+
# hold in @attributes, or passed options to notice_error which show up in
|
119
|
+
# @attributes_from_notice_error. Both need filtering, so merge them together
|
120
|
+
# in our Attributes class for consistent handling
|
121
|
+
def merged_custom_attributes
|
122
|
+
merged_attributes = NewRelic::Agent::Transaction::Attributes.new(NewRelic::Agent.instance.attribute_filter)
|
123
|
+
|
124
|
+
merge_custom_attributes_from_transaction(merged_attributes)
|
125
|
+
merge_custom_attributes_from_notice_error(merged_attributes)
|
126
|
+
|
127
|
+
merged_attributes.custom_attributes_for(DESTINATION)
|
128
|
+
end
|
129
|
+
|
130
|
+
def merge_custom_attributes_from_transaction(merged_attributes)
|
131
|
+
if @attributes
|
132
|
+
from_transaction = @attributes.custom_attributes_for(DESTINATION)
|
133
|
+
merged_attributes.merge_custom_attributes(from_transaction)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def merge_custom_attributes_from_notice_error(merged_attributes)
|
138
|
+
if @attributes_from_notice_error
|
139
|
+
from_notice_error = NewRelic::NoticedError.normalize_params(@attributes_from_notice_error)
|
140
|
+
merged_attributes.merge_custom_attributes(from_notice_error)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def build_agent_attributes
|
145
|
+
if @attributes
|
146
|
+
@attributes.agent_attributes_for(DESTINATION)
|
147
|
+
else
|
148
|
+
EMPTY_HASH
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def build_intrinsic_attributes
|
153
|
+
if @attributes
|
154
|
+
@attributes.intrinsic_attributes_for(DESTINATION)
|
155
|
+
else
|
156
|
+
EMPTY_HASH
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def append_attributes(outgoing_params, outgoing_key, source_attributes)
|
161
|
+
outgoing_params[outgoing_key] = source_attributes || {}
|
162
|
+
end
|
163
|
+
|
88
164
|
end
|
@@ -19,6 +19,15 @@ module NewRelic::Rack
|
|
19
19
|
# examine in order to look for a RUM insertion point.
|
20
20
|
SCAN_LIMIT = 50_000
|
21
21
|
|
22
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
23
|
+
CONTENT_DISPOSITION = 'Content-Disposition'.freeze
|
24
|
+
ATTACHMENT = 'attachment'.freeze
|
25
|
+
TEXT_HTML = 'text/html'.freeze
|
26
|
+
|
27
|
+
BODY_START = "<body".freeze
|
28
|
+
HEAD_START = "<head".freeze
|
29
|
+
GT = ">".freeze
|
30
|
+
|
22
31
|
def traced_call(env)
|
23
32
|
result = @app.call(env) # [status, headers, response]
|
24
33
|
|
@@ -50,11 +59,11 @@ module NewRelic::Rack
|
|
50
59
|
end
|
51
60
|
|
52
61
|
def is_html?(headers)
|
53
|
-
headers[
|
62
|
+
headers[CONTENT_TYPE] && headers[CONTENT_TYPE].include?(TEXT_HTML)
|
54
63
|
end
|
55
64
|
|
56
65
|
def is_attachment?(headers)
|
57
|
-
headers[
|
66
|
+
headers[CONTENT_DISPOSITION] && headers[CONTENT_DISPOSITION].include?(ATTACHMENT)
|
58
67
|
end
|
59
68
|
|
60
69
|
def is_streaming?(env)
|
@@ -99,10 +108,6 @@ module NewRelic::Rack
|
|
99
108
|
NewRelic::Agent.logger.debug(msg)
|
100
109
|
end
|
101
110
|
|
102
|
-
if headers['Content-Length']
|
103
|
-
headers['Content-Length'] = calculate_content_length(source).to_s
|
104
|
-
end
|
105
|
-
|
106
111
|
source
|
107
112
|
rescue => e
|
108
113
|
NewRelic::Agent.logger.debug "Skipping RUM instrumentation on exception.", e
|
@@ -124,7 +129,7 @@ module NewRelic::Rack
|
|
124
129
|
end
|
125
130
|
|
126
131
|
def find_body_start(beginning_of_source)
|
127
|
-
beginning_of_source.index(
|
132
|
+
beginning_of_source.index(BODY_START)
|
128
133
|
end
|
129
134
|
|
130
135
|
def find_x_ua_compatible_position(beginning_of_source)
|
@@ -138,18 +143,8 @@ module NewRelic::Rack
|
|
138
143
|
end
|
139
144
|
|
140
145
|
def find_end_of_head_open(beginning_of_source)
|
141
|
-
head_open = beginning_of_source.index(
|
142
|
-
beginning_of_source.index(
|
143
|
-
end
|
144
|
-
|
145
|
-
# String does not respond to 'bytesize' in 1.8.6. Fortunately String#length
|
146
|
-
# returns bytes rather than characters in 1.8.6 so we can use that instead.
|
147
|
-
def calculate_content_length(source)
|
148
|
-
if source.respond_to?(:bytesize)
|
149
|
-
source.bytesize
|
150
|
-
else
|
151
|
-
source.length
|
152
|
-
end
|
146
|
+
head_open = beginning_of_source.index(HEAD_START)
|
147
|
+
beginning_of_source.index(GT, head_open) + 1 if head_open
|
153
148
|
end
|
154
149
|
end
|
155
150
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
-
|
5
|
-
require 'rack'
|
6
4
|
require 'rack/request'
|
7
5
|
require 'rack/response'
|
8
6
|
require 'rack/file'
|
@@ -13,14 +11,7 @@ require 'new_relic/metric_parser/metric_parser'
|
|
13
11
|
require 'new_relic/rack/agent_middleware'
|
14
12
|
require 'new_relic/agent/instrumentation/middleware_proxy'
|
15
13
|
|
16
|
-
require 'new_relic/transaction_sample'
|
17
|
-
require 'new_relic/transaction_analysis'
|
18
|
-
|
19
14
|
module NewRelic
|
20
|
-
class TransactionSample
|
21
|
-
include TransactionAnalysis
|
22
|
-
end
|
23
|
-
|
24
15
|
module Rack
|
25
16
|
# This middleware provides the 'developer mode' feature of newrelic_rpm,
|
26
17
|
# which allows you to see data about local web transactions in development
|
@@ -41,6 +32,7 @@ module NewRelic
|
|
41
32
|
VIEW_PATH = File.expand_path('../../../../ui/views/' , __FILE__)
|
42
33
|
HELPER_PATH = File.expand_path('../../../../ui/helpers/', __FILE__)
|
43
34
|
require File.join(HELPER_PATH, 'developer_mode_helper.rb')
|
35
|
+
require 'new_relic/rack/developer_mode/segment_summary'
|
44
36
|
|
45
37
|
include NewRelic::DeveloperModeHelper
|
46
38
|
|
@@ -213,8 +205,8 @@ module NewRelic
|
|
213
205
|
|
214
206
|
return render(:sample_not_found) unless @sample
|
215
207
|
|
216
|
-
@request_params = @sample
|
217
|
-
@custom_params = @sample
|
208
|
+
@request_params = request_attributes_for(@sample)
|
209
|
+
@custom_params = custom_attributes_for(@sample)
|
218
210
|
|
219
211
|
controller_metric = @sample.transaction_name
|
220
212
|
|
@@ -222,7 +214,7 @@ module NewRelic
|
|
222
214
|
@sample_controller_name = metric_parser.controller_name
|
223
215
|
@sample_action_name = metric_parser.action_name
|
224
216
|
|
225
|
-
@sql_segments = @sample
|
217
|
+
@sql_segments = sql_segments(@sample)
|
226
218
|
if params['d']
|
227
219
|
@sql_segments.sort!{|a,b| b.duration <=> a.duration }
|
228
220
|
end
|
@@ -235,7 +227,7 @@ module NewRelic
|
|
235
227
|
|
236
228
|
def get_samples
|
237
229
|
@samples = NewRelic::Agent.instance.transaction_sampler.dev_mode_sample_buffer.samples.select do |sample|
|
238
|
-
sample.
|
230
|
+
sample.transaction_name != nil
|
239
231
|
end
|
240
232
|
|
241
233
|
return @samples = @samples.sort_by(&:duration).reverse if params['h']
|
@@ -260,8 +252,70 @@ module NewRelic
|
|
260
252
|
return unless @sample
|
261
253
|
|
262
254
|
segment_id = params['segment'].to_i
|
263
|
-
@segment = @sample.
|
255
|
+
@segment = @sample.root_node.find_node(segment_id)
|
256
|
+
end
|
257
|
+
|
258
|
+
def custom_attributes_for(sample)
|
259
|
+
sample.attributes.custom_attributes_for(NewRelic::Agent::AttributeFilter::DST_DEVELOPER_MODE)
|
260
|
+
end
|
261
|
+
|
262
|
+
REQUEST_PARAMETERS_PREFIX = "request.parameters".freeze
|
263
|
+
|
264
|
+
def request_attributes_for(sample)
|
265
|
+
agent_attributes = sample.attributes.agent_attributes_for(NewRelic::Agent::AttributeFilter::DST_DEVELOPER_MODE)
|
266
|
+
agent_attributes.inject({}) do |memo, (key, value)|
|
267
|
+
memo[key] = value if key.to_s.start_with?(REQUEST_PARAMETERS_PREFIX)
|
268
|
+
memo
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def breakdown_data(sample, limit = nil)
|
273
|
+
metric_hash = {}
|
274
|
+
sample.each_node_with_nest_tracking do |node|
|
275
|
+
unless node == sample.root_node
|
276
|
+
metric_name = node.metric_name
|
277
|
+
metric_hash[metric_name] ||= SegmentSummary.new(metric_name, sample)
|
278
|
+
metric_hash[metric_name] << node
|
279
|
+
metric_hash[metric_name]
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
data = metric_hash.values
|
284
|
+
|
285
|
+
data.sort! do |x,y|
|
286
|
+
y.exclusive_time <=> x.exclusive_time
|
287
|
+
end
|
288
|
+
|
289
|
+
if limit && data.length > limit
|
290
|
+
data = data[0..limit - 1]
|
291
|
+
end
|
292
|
+
|
293
|
+
# add one last node for the remaining time if any
|
294
|
+
remainder = sample.duration
|
295
|
+
data.each do |node|
|
296
|
+
remainder -= node.exclusive_time
|
297
|
+
end
|
298
|
+
|
299
|
+
if (remainder*1000).round > 0
|
300
|
+
remainder_summary = SegmentSummary.new('Remainder', sample)
|
301
|
+
remainder_summary.total_time = remainder_summary.exclusive_time = remainder
|
302
|
+
remainder_summary.call_count = 1
|
303
|
+
data << remainder_summary
|
304
|
+
end
|
305
|
+
|
306
|
+
data
|
264
307
|
end
|
308
|
+
|
309
|
+
# return an array of sql statements executed by this transaction
|
310
|
+
# each element in the array contains [sql, parent_segment_metric_name, duration]
|
311
|
+
def sql_segments(sample, show_non_sql_segments = true)
|
312
|
+
segments = []
|
313
|
+
sample.each_node do |segment|
|
314
|
+
segments << segment if segment[:sql] || segment[:sql_obfuscated] || (show_non_sql_segments && segment[:key])
|
315
|
+
end
|
316
|
+
segments
|
317
|
+
end
|
318
|
+
|
265
319
|
end
|
266
320
|
end
|
267
321
|
end
|