newrelic_rpm 9.11.0 → 9.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +1 -1
  4. data/lib/new_relic/agent/agent_logger.rb +1 -0
  5. data/lib/new_relic/agent/configuration/default_source.rb +106 -3
  6. data/lib/new_relic/agent/database/obfuscator.rb +1 -0
  7. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
  8. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +1 -1
  9. data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
  10. data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
  11. data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
  12. data/lib/new_relic/agent/instrumentation/logstasher.rb +27 -0
  13. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
  14. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
  15. data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
  16. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
  17. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
  18. data/lib/new_relic/agent/instrumentation/redis.rb +5 -0
  19. data/lib/new_relic/agent/local_log_decorator.rb +8 -1
  20. data/lib/new_relic/agent/log_event_aggregator.rb +91 -26
  21. data/lib/new_relic/control/instance_methods.rb +1 -0
  22. data/lib/new_relic/control/private_instance_methods.rb +4 -0
  23. data/lib/new_relic/control/security_interface.rb +57 -0
  24. data/lib/new_relic/control.rb +1 -1
  25. data/lib/new_relic/rack/browser_monitoring.rb +11 -7
  26. data/lib/new_relic/version.rb +1 -1
  27. data/lib/tasks/config.rake +5 -2
  28. data/lib/tasks/helpers/config.html.erb +1 -1
  29. data/lib/tasks/helpers/format.rb +1 -1
  30. data/lib/tasks/helpers/newrelicyml.rb +3 -2
  31. data/lib/tasks/instrumentation_generator/instrumentation.thor +1 -0
  32. data/newrelic.yml +200 -137
  33. data/test/agent_helper.rb +9 -0
  34. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc36449c6f2ea3322f353181809c05d3e84e28f85fb15544c82e088946384046
4
- data.tar.gz: f8fa907597f05f47c5dbe9c38a005cb1d09f971183aa7075664e6ade029186fc
3
+ metadata.gz: 3c551a88ec42cceb53ade85126fe41272598c367b11d70e5167d374556b6fe8d
4
+ data.tar.gz: 912ff4f8d33e2ba318b4ec74fa8a3e0680c21fda3521a2382658855219ec81d6
5
5
  SHA512:
6
- metadata.gz: 622cdf275eb70aa1f57e027f2e73559855c17c4351741c80ec0db8ae45b773f2d7aa2831ae562e228b24a71a0532ae93dced167be3ecfdd3561886224d212070
7
- data.tar.gz: a68a148e494bfc0e5f9da3c369eb56f7170664e78ffd12cc178e77b7361da39edefbc967b5c71c2905b993b5d4075b2189abc3ec7692081d6b4dd422149902f3
6
+ metadata.gz: 61472afe9cf52eea1a86e4394b613666372c6a0086ea1173c28d8341ff417cf980feb6fd7a25f23ec2e78bb02cc4a32efeb5102f1f42175300d0a0f8ba7eea1b
7
+ data.tar.gz: e3de1701d6f580a18ceb05c1607d3eada9081012e6bc8edec503b2e945d7128312224c63604dd40debb8554fcc13621a731251f4e349dbcdef909cf09c60c867
data/CHANGELOG.md CHANGED
@@ -1,5 +1,79 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v9.12.0
4
+
5
+ Version 9.12.0 adds support for the `newrelic_security` agent, introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails.
6
+
7
+ - **Feature: Add support for the newrelic_security agent**
8
+
9
+ [New Relic Interactive Application Security Testing (IAST)](https://docs.newrelic.com/docs/iast/introduction/) can help you prevent cyberattacks and breaches on your applications by probing your running code for exploitable vulnerabilities.
10
+
11
+ The `newrelic_security` gem provides this feature for Ruby. It depends on `newrelic_rpm`. This is the first version of `newrelic_rpm` compatible with `newrelic_security`.
12
+
13
+ At this time, the security agent is intended for use only within a dedicated security testing environment with data that can tolerate modification or deletion. The security agent is available as a separate Ruby gem, `newrelic_security`. It is recommended that this separate gem only be introduced to a security testing environment by leveraging Bundler grouping like so:
14
+
15
+ ```ruby
16
+ # Gemfile
17
+ gem 'newrelic_rpm' # New Relic APM observability agent
18
+ gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing
19
+
20
+ group :security do
21
+ gem 'newrelic_security', require: false # New Relic security agent
22
+ end
23
+ ```
24
+
25
+ In order to run the security agent, you need to update your configuration. At a minimum, `security.agent.enabled` and `security.enabled` must be set to `true`. They are `false` by default. Similar to the gem installation, we recommend you set these configurations for a special security testing environment only.
26
+
27
+ Here's an example using `newrelic.yml`:
28
+
29
+ ```yaml
30
+ common: &default_settings
31
+ license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
32
+ app_name: "Example app"
33
+
34
+ development:
35
+ <<: *default_settings
36
+ app_name: <%= app_name %> (Development)
37
+
38
+ security:
39
+ <<: *default_settings
40
+ security.enabled: true
41
+ security.agent.enabled: true
42
+
43
+ production:
44
+ <<: *default_settings
45
+ ```
46
+
47
+ The following configuration relate to the `newrelic_security` gem:
48
+
49
+ | Configuration name | Default | Behavior |
50
+ | ------------------ | ------- |----------|
51
+ | security.agent.enabled | `false` | If `true`, the security agent is loaded (a Ruby 'require' is performed) |
52
+ | security.enabled | `false` | If `true`, the security agent is started (the agent runs in its event loop) |
53
+ | security.mode | `'IAST'` | Defines the mode for the security agent to operate in. Currently only 'IAST' is supported |
54
+ | security.validator_service_url | `'wss://csec.nr-data.net'` | Defines the endpoint URL for posting security related data |
55
+ | security.detection.rci.enabled | `true` | If `true`, enables RCI (remote code injection) detection |
56
+ | security.detection.rxss.enabled | `true` | If `true`, enables RXSS (reflected cross-site scripting) detection |
57
+ | security.detection.deserialization.enabled | `true` | If `true`, enables deserialization detection |
58
+ | security.application_info.port | `nil` | An Integer representing the port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default. |
59
+
60
+ - **Feature: Add instrumentation for LogStasher**
61
+
62
+ The agent will now record logs generated by [LogStasher](https://github.com/shadabahmed/logstasher). Versions 1.0.0 and above of the LogStasher gem are supported. [PR#2559](https://github.com/newrelic/newrelic-ruby-agent/pull/2559)
63
+
64
+ - **Feature: Add instrumentation for redis-clustering**
65
+
66
+ Version 5.x of the `redis` gem moved cluster behavior into a different gem, `redis-clustering`. This gem can access instrumentation registered through `RedisClient::Middleware`. Previously, the agent only instrumented the `call_pipelined` method through this approach, but now users of the `redis-clustering` gem will also have instrumentation registered for `connect` and `call` methods. In addition, the way the `database_name` attribute is set for Redis datastore spans is now compatible with all versions of Redis supported by the New Relic Ruby agent. Thank you, [@praveen-ks](https://github.com/praveen-ks) for bringing this to our attention. [Issue#2444](https://github.com/newrelic/newrelic-ruby-agent/issues/2444) [PR#2720](https://github.com/newrelic/newrelic-ruby-agent/pull/2720)
67
+
68
+ - **Bugfix: Update Elasticsearch instrumentation to only attempt to get the cluster name once per client**
69
+
70
+ Previously, the agent would attempt to get the cluster name every time a call was made if it was not already captured. This could lead to a large number of failures if the cluster name could not be retrieved. Now, the agent will only attempt to get the cluster name once per client, even if it fails. Thank you, [@ascoppa](https://github.com/ascoppa) for bringing this to our attention. [Issue#2730](https://github.com/newrelic/newrelic-ruby-agent/issues/2730) [PR#2743](https://github.com/newrelic/newrelic-ruby-agent/pull/2743)
71
+
72
+ - **Feature: Produce metrics for 4 additional Action Controller Rails notifications**
73
+
74
+ Four additional Action Controller related Rails notifications are now subscribed to by the agent to produce telemetry. These 4 are `exist_fragment?`, `expire_fragment`, `read_fragment`, and `write_fragment`. As with instrumentation for Action Controller itself, these notifications are enabled by default and can be disabled by setting `:disable_action_controller` to `true` in the agent's `newrelic.yml` configuration file. [PR#2745](https://github.com/newrelic/newrelic-ruby-agent/pull/2745)
75
+
76
+
3
77
  ## v9.11.0
4
78
 
5
79
  Version 9.11.0 introduces instrumentation for the aws-sdk-sqs gem, fixes a bug related to expected errors not bearing a "true" value for the "expected" attribute if expected as a result of an HTTP status code match and changes the way Stripe instrumentation metrics are named to prevent high-cardinality issues.
data/README.md CHANGED
@@ -24,7 +24,7 @@ You can also monitor non-web applications. Refer to the "Other
24
24
  Environments" section below.
25
25
 
26
26
  We offer an AWS Lambda layer for instrumenting your serverless Ruby functions.
27
- Details can be found on our [getting started guide](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/).
27
+ Details can be found on our [getting started guide](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/instrument-your-own/).
28
28
 
29
29
  ## Installing and Using
30
30
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'thread'
6
6
  require 'logger'
7
+ require 'singleton'
7
8
  require 'new_relic/agent/hostname'
8
9
  require 'new_relic/agent/log_once'
9
10
  require 'new_relic/agent/instrumentation/logger/instrumentation'
@@ -72,7 +72,7 @@ module NewRelic
72
72
  value_from_defaults(key, :transform)
73
73
  end
74
74
 
75
- def self.config_search_paths # rubocop:disable Metrics/AbcSize
75
+ def self.config_search_paths
76
76
  proc {
77
77
  yaml = 'newrelic.yml'
78
78
  config_yaml = File.join('config', yaml)
@@ -1112,7 +1112,7 @@ module NewRelic
1112
1112
  :public => true,
1113
1113
  :type => Boolean,
1114
1114
  :allowed_from_server => true,
1115
- :description => "If `true`, the agent will report source code level metrics for traced methods.\nsee: " \
1115
+ :description => "If `true`, the agent will report source code level metrics for traced methods.\nSee: " \
1116
1116
  'https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/'
1117
1117
  },
1118
1118
  # Cross application tracer
@@ -1150,7 +1150,7 @@ module NewRelic
1150
1150
  :allowed_from_server => true,
1151
1151
  :dynamic_name => true,
1152
1152
  :description => <<~DESC
1153
- * Specify a maximum number of custom events to buffer in memory at a time.'
1153
+ * Specify a maximum number of custom events to buffer in memory at a time.
1154
1154
  * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), \
1155
1155
  set to max value `100000`. This ensures the agent captures the maximum amount of LLM events.
1156
1156
  DESC
@@ -1444,6 +1444,7 @@ module NewRelic
1444
1444
  },
1445
1445
  :'instrumentation.async_http' => {
1446
1446
  :default => 'auto',
1447
+ :documentation_default => 'auto',
1447
1448
  :public => true,
1448
1449
  :type => String,
1449
1450
  :dynamic_name => true,
@@ -1452,6 +1453,7 @@ module NewRelic
1452
1453
  },
1453
1454
  :'instrumentation.bunny' => {
1454
1455
  :default => 'auto',
1456
+ :documentation_default => 'auto',
1455
1457
  :public => true,
1456
1458
  :type => String,
1457
1459
  :dynamic_name => true,
@@ -1468,6 +1470,7 @@ module NewRelic
1468
1470
  },
1469
1471
  :'instrumentation.dynamodb' => {
1470
1472
  :default => 'auto',
1473
+ :documentation_default => 'auto',
1471
1474
  :public => true,
1472
1475
  :type => String,
1473
1476
  :dynamic_name => true,
@@ -1476,6 +1479,7 @@ module NewRelic
1476
1479
  },
1477
1480
  :'instrumentation.fiber' => {
1478
1481
  :default => 'auto',
1482
+ :documentation_default => 'auto',
1479
1483
  :public => true,
1480
1484
  :type => String,
1481
1485
  :dynamic_name => true,
@@ -1484,6 +1488,7 @@ module NewRelic
1484
1488
  },
1485
1489
  :'instrumentation.concurrent_ruby' => {
1486
1490
  :default => 'auto',
1491
+ :documentation_default => 'auto',
1487
1492
  :public => true,
1488
1493
  :type => String,
1489
1494
  :dynamic_name => true,
@@ -1510,6 +1515,7 @@ module NewRelic
1510
1515
  },
1511
1516
  :'instrumentation.elasticsearch' => {
1512
1517
  :default => 'auto',
1518
+ :documentation_default => 'auto',
1513
1519
  :public => true,
1514
1520
  :type => String,
1515
1521
  :dynamic_name => true,
@@ -1518,6 +1524,7 @@ module NewRelic
1518
1524
  },
1519
1525
  :'instrumentation.ethon' => {
1520
1526
  :default => 'auto',
1527
+ :documentation_default => 'auto',
1521
1528
  :public => true,
1522
1529
  :type => String,
1523
1530
  :dynamic_name => true,
@@ -1535,6 +1542,7 @@ module NewRelic
1535
1542
  },
1536
1543
  :'instrumentation.grape' => {
1537
1544
  :default => 'auto',
1545
+ :documentation_default => 'auto',
1538
1546
  :public => true,
1539
1547
  :type => String,
1540
1548
  :dynamic_name => true,
@@ -1603,8 +1611,18 @@ module NewRelic
1603
1611
  :allowed_from_server => false,
1604
1612
  :description => 'Controls auto-instrumentation of Ruby standard library Logger at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1605
1613
  },
1614
+ :'instrumentation.logstasher' => {
1615
+ :default => instrumentation_value_from_boolean(:'application_logging.enabled'),
1616
+ :documentation_default => 'auto',
1617
+ :public => true,
1618
+ :type => String,
1619
+ :dynamic_name => true,
1620
+ :allowed_from_server => false,
1621
+ :description => 'Controls auto-instrumentation of the LogStasher library at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1622
+ },
1606
1623
  :'instrumentation.memcache' => {
1607
1624
  :default => 'auto',
1625
+ :documentation_default => 'auto',
1608
1626
  :public => true,
1609
1627
  :type => String,
1610
1628
  :dynamic_name => true,
@@ -1698,6 +1716,7 @@ module NewRelic
1698
1716
  },
1699
1717
  :'instrumentation.rake' => {
1700
1718
  :default => 'auto',
1719
+ :documentation_default => 'auto',
1701
1720
  :public => true,
1702
1721
  :type => String,
1703
1722
  :dynamic_name => true,
@@ -1706,6 +1725,7 @@ module NewRelic
1706
1725
  },
1707
1726
  :'instrumentation.redis' => {
1708
1727
  :default => 'auto',
1728
+ :documentation_default => 'auto',
1709
1729
  :public => true,
1710
1730
  :type => String,
1711
1731
  :dynamic_name => true,
@@ -1723,6 +1743,7 @@ module NewRelic
1723
1743
  },
1724
1744
  :'instrumentation.roda' => {
1725
1745
  :default => 'auto',
1746
+ :documentation_default => 'auto',
1726
1747
  :public => true,
1727
1748
  :type => String,
1728
1749
  :dynamic_name => true,
@@ -1731,6 +1752,7 @@ module NewRelic
1731
1752
  },
1732
1753
  :'instrumentation.sinatra' => {
1733
1754
  :default => 'auto',
1755
+ :documentation_default => 'auto',
1734
1756
  :public => true,
1735
1757
  :type => String,
1736
1758
  :dynamic_name => true,
@@ -1746,6 +1768,7 @@ module NewRelic
1746
1768
  },
1747
1769
  :'instrumentation.view_component' => {
1748
1770
  :default => 'auto',
1771
+ :documentation_default => 'auto',
1749
1772
  :public => true,
1750
1773
  :type => String,
1751
1774
  :dynamic_name => true,
@@ -1782,6 +1805,7 @@ module NewRelic
1782
1805
  },
1783
1806
  :'instrumentation.thread' => {
1784
1807
  :default => 'auto',
1808
+ :documentation_default => 'auto',
1785
1809
  :public => true,
1786
1810
  :type => String,
1787
1811
  :dynamic_name => true,
@@ -1804,6 +1828,7 @@ module NewRelic
1804
1828
  },
1805
1829
  :'instrumentation.tilt' => {
1806
1830
  :default => 'auto',
1831
+ :documentation_default => 'auto',
1807
1832
  :public => true,
1808
1833
  :type => String,
1809
1834
  :dynamic_name => true,
@@ -2514,6 +2539,84 @@ module NewRelic
2514
2539
  :type => Integer,
2515
2540
  :allowed_from_server => false,
2516
2541
  :description => 'This value represents the total amount of memory available to the host (not the process), in mebibytes (1024 squared or 1,048,576 bytes).'
2542
+ },
2543
+ # security agent
2544
+ :'security.agent.enabled' => {
2545
+ :default => false,
2546
+ :external => true,
2547
+ :public => true,
2548
+ :type => Boolean,
2549
+ :allowed_from_server => false,
2550
+ :description => "If `true`, the security agent is loaded (a Ruby 'require' is performed)"
2551
+ },
2552
+ :'security.enabled' => {
2553
+ :default => false,
2554
+ :external => true,
2555
+ :public => true,
2556
+ :type => Boolean,
2557
+ :allowed_from_server => false,
2558
+ :description => 'If `true`, the security agent is started (the agent runs in its event loop)'
2559
+ },
2560
+ :'security.mode' => {
2561
+ :default => 'IAST',
2562
+ :external => true,
2563
+ :public => true,
2564
+ :type => String,
2565
+ :allowed_from_server => true,
2566
+ :allowlist => %w[IAST RASP],
2567
+ :description => 'Defines the mode for the security agent to operate in. Currently only `IAST` is supported',
2568
+ :dynamic_name => true
2569
+ },
2570
+ :'security.validator_service_url' => {
2571
+ :default => 'wss://csec.nr-data.net',
2572
+ :external => true,
2573
+ :public => true,
2574
+ :type => String,
2575
+ :allowed_from_server => true,
2576
+ :description => 'Defines the endpoint URL for posting security-related data',
2577
+ :dynamic_name => true
2578
+ },
2579
+ :'security.detection.rci.enabled' => {
2580
+ :default => true,
2581
+ :external => true,
2582
+ :public => true,
2583
+ :type => Boolean,
2584
+ :allowed_from_server => false,
2585
+ :description => 'If `true`, enables RCI (remote code injection) detection'
2586
+ },
2587
+ :'security.detection.rxss.enabled' => {
2588
+ :default => true,
2589
+ :external => true,
2590
+ :public => true,
2591
+ :type => Boolean,
2592
+ :allowed_from_server => false,
2593
+ :description => 'If `true`, enables RXSS (reflected cross-site scripting) detection'
2594
+ },
2595
+ :'security.detection.deserialization.enabled' => {
2596
+ :default => true,
2597
+ :external => true,
2598
+ :public => true,
2599
+ :type => Boolean,
2600
+ :allowed_from_server => false,
2601
+ :description => 'If `true`, enables deserialization detection'
2602
+ },
2603
+ :'security.application_info.port' => {
2604
+ :default => nil,
2605
+ :allow_nil => true,
2606
+ :public => true,
2607
+ :type => Integer,
2608
+ :external => true,
2609
+ :allowed_from_server => false,
2610
+ :description => 'The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default.'
2611
+ },
2612
+ :'security.request.body_limit' => {
2613
+ :default => 300,
2614
+ :allow_nil => true,
2615
+ :public => true,
2616
+ :type => Integer,
2617
+ :external => true,
2618
+ :allowed_from_server => false,
2619
+ :description => 'Defines the request body limit to process in security events (in KB). The default value is 300, for 300KB.'
2517
2620
  }
2518
2621
  }.freeze
2519
2622
  # rubocop:enable Metrics/CollectionLiteralLength
@@ -2,6 +2,7 @@
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
4
 
5
+ require 'singleton'
5
6
  require 'new_relic/agent/database/obfuscation_helpers'
6
7
 
7
8
  module NewRelic
@@ -48,6 +48,12 @@ module NewRelic
48
48
  correlation_id: opts[:correlation_id],
49
49
  exchange_type: type
50
50
  )
51
+ if segment
52
+ segment.add_agent_attribute('server.address', channel&.connection&.hostname)
53
+ segment.add_agent_attribute('server.port', channel&.connection&.port)
54
+ segment.add_agent_attribute('messaging.destination.name', destination) # for produce, this is exchange name
55
+ segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', opts[:routing_key])
56
+ end
51
57
  rescue => e
52
58
  NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Exchange#publish', e)
53
59
  yield
@@ -94,6 +100,14 @@ module NewRelic
94
100
  queue_name: name,
95
101
  start_time: t0
96
102
  )
103
+ if segment
104
+ segment.add_agent_attribute('server.address', channel&.connection&.hostname)
105
+ segment.add_agent_attribute('server.port', channel&.connection&.port)
106
+ segment.add_agent_attribute('messaging.destination.name', name) # for consume, this is queue name
107
+ segment.add_agent_attribute('messaging.destination_publish.name', exch_name)
108
+ segment.add_agent_attribute('message.queueName', name)
109
+ segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', delivery_info&.routing_key)
110
+ end
97
111
  rescue => e
98
112
  NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Queue#pop', e)
99
113
  else
@@ -102,7 +102,7 @@ module NewRelic::Agent::Instrumentation
102
102
  end
103
103
 
104
104
  def nr_cluster_name
105
- return @nr_cluster_name if @nr_cluster_name
105
+ return @nr_cluster_name if defined?(@nr_cluster_name)
106
106
  return if nr_hosts.empty?
107
107
 
108
108
  NewRelic::Agent.disable_all_tracing do
@@ -0,0 +1,21 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module LogStasher::Chain
7
+ def self.instrument!
8
+ ::LogStasher.singleton_class.class_eval do
9
+ include NewRelic::Agent::Instrumentation::LogStasher
10
+
11
+ alias_method(:build_logstash_event_without_new_relic, :build_logstash_event)
12
+
13
+ def build_logstash_event(*args)
14
+ build_logstash_event_with_new_relic(*args) do
15
+ build_logstash_event_without_new_relic(*args)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module LogStasher
7
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
8
+
9
+ def self.enabled?
10
+ NewRelic::Agent.config[:'instrumentation.logstasher'] != 'disabled'
11
+ end
12
+
13
+ def build_logstash_event_with_new_relic(*args)
14
+ logstasher_event = yield
15
+ log = logstasher_event.instance_variable_get(:@data)
16
+
17
+ ::NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
18
+ ::NewRelic::Agent.agent.log_event_aggregator.record_logstasher_event(log)
19
+ ::NewRelic::Agent::LocalLogDecorator.decorate(log)
20
+
21
+ logstasher_event
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module LogStasher::Prepend
7
+ include NewRelic::Agent::Instrumentation::LogStasher
8
+
9
+ def build_logstash_event(*args)
10
+ build_logstash_event_with_new_relic(*args) { super }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'logstasher/instrumentation'
6
+ require_relative 'logstasher/chain'
7
+ require_relative 'logstasher/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :logstasher
11
+
12
+ depends_on do
13
+ defined?(LogStasher) &&
14
+ Gem::Version.new(LogStasher::VERSION) >= Gem::Version.new('1.0.0') &&
15
+ NewRelic::Agent.config[:'application_logging.enabled']
16
+ end
17
+
18
+ executes do
19
+ NewRelic::Agent.logger.info('Installing LogStasher instrumentation')
20
+
21
+ if use_prepend?
22
+ prepend_instrument LogStasher.singleton_class, NewRelic::Agent::Instrumentation::LogStasher::Prepend
23
+ else
24
+ chain_instrument NewRelic::Agent::Instrumentation::LogStasher::Chain
25
+ end
26
+ end
27
+ end
@@ -13,6 +13,7 @@ module NewRelic
13
13
  attr_accessor :_nr_deferred_detection_ran
14
14
  end
15
15
  builder_class._nr_deferred_detection_ran = false
16
+ NewRelic::Control::SecurityInterface.instance.wait = true
16
17
  end
17
18
 
18
19
  def deferred_dependency_check
@@ -21,6 +22,8 @@ module NewRelic
21
22
  NewRelic::Agent.logger.info('Doing deferred dependency-detection before Rack startup')
22
23
  DependencyDetection.detect!
23
24
  self.class._nr_deferred_detection_ran = true
25
+ NewRelic::Control::SecurityInterface.instance.wait = false
26
+ NewRelic::Control::SecurityInterface.instance.init_agent
24
27
  end
25
28
 
26
29
  def check_for_late_instrumentation(app)
@@ -32,15 +32,19 @@ DependencyDetection.defer do
32
32
  NewRelic::Agent::Instrumentation::ActionControllerSubscriber \
33
33
  .subscribe(/^process_action.action_controller$/)
34
34
 
35
- subs = %w[send_file
35
+ subs = %w[exist_fragment?
36
+ expire_fragment
37
+ halted_callback
38
+ read_fragment
39
+ redirect_to
36
40
  send_data
41
+ send_file
37
42
  send_stream
38
- redirect_to
39
- halted_callback
40
- unpermitted_parameters]
43
+ write_fragment
44
+ unpermitted_parameters].map { |s| Regexp.escape(s) }
41
45
 
42
46
  # have to double escape period because its going from string -> regex
43
47
  NewRelic::Agent::Instrumentation::ActionControllerOtherSubscriber \
44
- .subscribe(Regexp.new("^(#{subs.join('|')})\\.action_controller$"))
48
+ .subscribe(Regexp.new("^(?:#{subs.join('|')})\\.action_controller$"))
45
49
  end
46
50
  end
@@ -0,0 +1,26 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module RedisClient
7
+ module ClusterMiddleware
8
+ include NewRelic::Agent::Instrumentation::Redis
9
+
10
+ # Until we decide to move our Redis instrumentation entirely off patches
11
+ # keep the middleware instrumentation for the call and connect methods
12
+ # limited to the redis-clustering instrumentation.
13
+ #
14
+ # Redis's middleware option does not capture errors as high in the stack
15
+ # as our patches. Leaving the patches for call and connect on the main
16
+ # Redis gem limits the feature disparity our customers experience.
17
+ def call(*args, &block)
18
+ call_with_tracing(args[0]) { super }
19
+ end
20
+
21
+ def connect(*args, &block)
22
+ connect_with_tracing { super }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -9,14 +9,14 @@ module NewRelic::Agent::Instrumentation
9
9
  INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
10
10
 
11
11
  def connect_with_tracing
12
- with_tracing(Constants::CONNECT, database: db) { yield }
12
+ with_tracing(Constants::CONNECT, database: _nr_db) { yield }
13
13
  end
14
14
 
15
15
  def call_with_tracing(command, &block)
16
16
  operation = command[0]
17
17
  statement = ::NewRelic::Agent::Datastores::Redis.format_command(command)
18
18
 
19
- with_tracing(operation, statement: statement, database: db) { yield }
19
+ with_tracing(operation, statement: statement, database: _nr_db) { yield }
20
20
  end
21
21
 
22
22
  # Used for Redis 4.x and 3.x
@@ -24,22 +24,15 @@ module NewRelic::Agent::Instrumentation
24
24
  operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
25
25
  statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
26
26
 
27
- with_tracing(operation, statement: statement, database: db) { yield }
27
+ with_tracing(operation, statement: statement, database: _nr_db) { yield }
28
28
  end
29
29
 
30
30
  # Used for Redis 5.x+
31
31
  def call_pipelined_with_tracing(pipeline)
32
- db = begin
33
- _nr_redis_client_config.db
34
- rescue StandardError => e
35
- NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}")
36
- nil
37
- end
38
-
39
32
  operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
40
33
  statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline)
41
34
 
42
- with_tracing(operation, statement: statement, database: db) { yield }
35
+ with_tracing(operation, statement: statement, database: _nr_db) { yield }
43
36
  end
44
37
 
45
38
  private
@@ -94,5 +87,15 @@ module NewRelic::Agent::Instrumentation
94
87
  config
95
88
  end
96
89
  end
90
+
91
+ def _nr_db
92
+ # db is a method on the Redis client in versions < 5.x
93
+ return db if respond_to?(:db)
94
+ # db is accessible through the RedisClient::Config object in versions > 5.x
95
+ return _nr_redis_client_config.db if _nr_redis_client_config.respond_to?(:db)
96
+ rescue StandardError => e
97
+ NewRelic::Agent.logger.debug("Failed to determine configured Redis db value: #{e.class} - #{e.message}")
98
+ nil
99
+ end
97
100
  end
98
101
  end
@@ -6,6 +6,9 @@ module NewRelic::Agent::Instrumentation
6
6
  module RedisClient
7
7
  module Middleware
8
8
  # This module is used to instrument Redis 5.x+
9
+ #
10
+ # It only instruments call_pipelined because connect and call are accessed
11
+ # too late in the stack to capture all errors
9
12
  include NewRelic::Agent::Instrumentation::Redis
10
13
 
11
14
  def call_pipelined(*args, &block)
@@ -10,6 +10,7 @@ require_relative 'redis/chain'
10
10
  require_relative 'redis/constants'
11
11
  require_relative 'redis/prepend'
12
12
  require_relative 'redis/middleware'
13
+ require_relative 'redis/cluster_middleware'
13
14
 
14
15
  DependencyDetection.defer do
15
16
  # Why not :redis? newrelic-redis used that name, so avoid conflicting
@@ -33,6 +34,10 @@ DependencyDetection.defer do
33
34
  NewRelic::Agent.logger.info('Installing Redis Instrumentation')
34
35
  if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT
35
36
  RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
37
+
38
+ if defined?(Redis::Cluster::Client)
39
+ return RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware)
40
+ end
36
41
  end
37
42
 
38
43
  if use_prepend?