newrelic_rpm 8.5.0 → 8.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -1
  3. data/LICENSE +0 -6
  4. data/README.md +16 -18
  5. data/THIRD_PARTY_NOTICES.md +14 -199
  6. data/lib/new_relic/agent/agent.rb +21 -0
  7. data/lib/new_relic/agent/agent_logger.rb +7 -0
  8. data/lib/new_relic/agent/audit_logger.rb +4 -0
  9. data/lib/new_relic/agent/configuration/default_source.rb +72 -14
  10. data/lib/new_relic/agent/configuration/event_harvest_config.rb +4 -2
  11. data/lib/new_relic/agent/configuration/server_source.rb +1 -0
  12. data/lib/new_relic/agent/hostname.rb +16 -10
  13. data/lib/new_relic/agent/instrumentation/active_support_logger/chain.rb +23 -0
  14. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +20 -0
  15. data/lib/new_relic/agent/instrumentation/active_support_logger/prepend.rb +12 -0
  16. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +24 -0
  17. data/lib/new_relic/agent/instrumentation/curb/chain.rb +1 -1
  18. data/lib/new_relic/agent/instrumentation/curb/prepend.rb +1 -1
  19. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +18 -18
  20. data/lib/new_relic/agent/instrumentation/logger.rb +4 -3
  21. data/lib/new_relic/agent/linking_metadata.rb +45 -0
  22. data/lib/new_relic/agent/local_log_decorator.rb +37 -0
  23. data/lib/new_relic/agent/log_event_aggregator.rb +234 -0
  24. data/lib/new_relic/agent/log_priority.rb +20 -0
  25. data/lib/new_relic/agent/new_relic_service.rb +14 -7
  26. data/lib/new_relic/agent/pipe_service.rb +4 -0
  27. data/lib/new_relic/agent/samplers/memory_sampler.rb +6 -1
  28. data/lib/new_relic/agent/transaction.rb +11 -0
  29. data/lib/new_relic/agent.rb +4 -14
  30. data/lib/new_relic/helper.rb +40 -0
  31. data/lib/new_relic/version.rb +1 -1
  32. data/lib/tasks/config.rake +3 -3
  33. data/newrelic.yml +20 -4
  34. data/newrelic_rpm.gemspec +1 -0
  35. data/test/agent_helper.rb +18 -4
  36. metadata +24 -3
  37. data/ROADMAP.md +0 -24
@@ -38,6 +38,12 @@ module NewRelic
38
38
  end
39
39
  end
40
40
 
41
+ def self.instrumentation_value_from_boolean(key)
42
+ Proc.new do
43
+ NewRelic::Agent.config[key] ? 'auto' : 'disabled'
44
+ end
45
+ end
46
+
41
47
  # Marks the config option as deprecated in the documentation once generated.
42
48
  # Does not appear in logs.
43
49
  def self.deprecated_description new_setting, description
@@ -354,21 +360,21 @@ module NewRelic
354
360
  :public => false,
355
361
  :type => String,
356
362
  :allowed_from_server => true,
357
- :description => 'The [Entity GUID](/attribute-dictionary/span/entityguid) for the entity running this agent.'
363
+ :description => 'The [Entity GUID](/attribute-dictionary/span/entityguid) for the entity running your agent.'
358
364
  },
359
365
  :monitor_mode => {
360
366
  :default => value_of(:enabled),
361
367
  :public => true,
362
368
  :type => Boolean,
363
369
  :allowed_from_server => false,
364
- :description => 'When `true`, the agent transmits data about your app to the New Relic [collector](/docs/using-new-relic/welcome-new-relic/get-started/glossary/#collector).'
370
+ :description => 'When `true`, the agent transmits data about your application to the New Relic [collector](/docs/using-new-relic/welcome-new-relic/get-started/glossary/#collector).'
365
371
  },
366
372
  :test_mode => {
367
373
  :default => false,
368
374
  :public => false,
369
375
  :type => Boolean,
370
376
  :allowed_from_server => false,
371
- :description => 'Used in tests for agent to start up but not connect to collector. Formerly used `developer_mode` in test config for this purpose.'
377
+ :description => 'Used in tests for the agent to start up, but not connect to the collector. Formerly used `developer_mode` in test config for this purpose.'
372
378
  },
373
379
  :log_level => {
374
380
  :default => 'info',
@@ -680,6 +686,14 @@ module NewRelic
680
686
  :allowed_from_server => true,
681
687
  :description => 'Number of seconds betwixt connections to the New Relic error event collection services.'
682
688
  },
689
+ :'event_report_period.log_event_data' => {
690
+ :default => 60,
691
+ :public => false,
692
+ :type => Integer,
693
+ :dynamic_name => true,
694
+ :allowed_from_server => true,
695
+ :description => 'Number of seconds betwixt connections to the New Relic log event collection services.'
696
+ },
683
697
  :'event_report_period.span_event_data' => {
684
698
  :default => 60,
685
699
  :public => false,
@@ -1004,7 +1018,7 @@ module NewRelic
1004
1018
  :description => 'Controls auto-instrumentation of dalli gem for Memcache at start up. May be one of [auto|prepend|chain|disabled].'
1005
1019
  },
1006
1020
  :'instrumentation.logger' => {
1007
- :default => "auto",
1021
+ :default => instrumentation_value_from_boolean(:'application_logging.enabled'),
1008
1022
  :public => true,
1009
1023
  :type => String,
1010
1024
  :dynamic_name => true,
@@ -1017,7 +1031,7 @@ module NewRelic
1017
1031
  :type => String,
1018
1032
  :dynamic_name => true,
1019
1033
  :allowed_from_server => false,
1020
- :description => 'Controls auto-instrumentation of Tilt at start up. May be one of [auto|prepend|chain|disabled].'
1034
+ :description => 'Controls auto-instrumentation of the Tilt template rendering library at start up. May be one of [auto|prepend|chain|disabled].'
1021
1035
  },
1022
1036
  :disable_data_mapper => {
1023
1037
  :default => false,
@@ -1390,7 +1404,7 @@ module NewRelic
1390
1404
  :public => true,
1391
1405
  :type => Integer,
1392
1406
  :allowed_from_server => true,
1393
- :description => 'Defines the maximum number of [TransactionError events](/docs/insights/new-relic-insights/decorating-events/error-event-default-attributes-insights) sent to Insights per harvest cycle.'
1407
+ :description => 'Defines the maximum number of [TransactionError events](/docs/insights/new-relic-insights/decorating-events/error-event-default-attributes-insights) reported per harvest cycle.'
1394
1408
  },
1395
1409
  :'rum.enabled' => {
1396
1410
  :default => true,
@@ -1508,7 +1522,7 @@ module NewRelic
1508
1522
  :deprecated => true,
1509
1523
  :description => deprecated_description(
1510
1524
  :'distributed_tracing-enabled',
1511
- 'If `true`, enables [cross-application tracing](/docs/agents/ruby-agent/features/cross-application-tracing-ruby/)'
1525
+ 'If `true`, enables [cross-application tracing](/docs/agents/ruby-agent/features/cross-application-tracing-ruby/) when `distributed_tracing.enabled` is set to `false`.'
1512
1526
  )
1513
1527
  },
1514
1528
  :cross_application_tracing => {
@@ -1803,7 +1817,7 @@ module NewRelic
1803
1817
  :public => true,
1804
1818
  :type => String,
1805
1819
  :allowed_from_server => false,
1806
- :description => 'A dictionary of [label names](/docs/data-analysis/user-interface-functions/labels-categories-organize-your-apps-servers) and values that will be applied to the data sent from this agent. May also be expressed as a semicolon-delimited `;` string of colon-separated `:` pairs. For example, `<var>Server</var>:<var>One</var>;<var>Data Center</var>:<var>Primary</var>`.'
1820
+ :description => 'A dictionary of [label names](/docs/data-analysis/user-interface-functions/labels-categories-organize-your-apps-servers) and values that will be applied to the data sent from your agent. May also be expressed as a semicolon-delimited `;` string of colon-separated `:` pairs. For example, `<var>Server</var>:<var>One</var>;<var>Data Center</var>:<var>Primary</var>`.'
1807
1821
  },
1808
1822
  :aggressive_keepalive => {
1809
1823
  :default => true,
@@ -1833,7 +1847,7 @@ module NewRelic
1833
1847
  :type => Array,
1834
1848
  :allowed_from_server => true,
1835
1849
  :transform => DefaultSource.method(:convert_to_regexp_list),
1836
- :description => 'Define transactions you want the agent to ignore, by specifying a list of patterns matching the URI you want to ignore.'
1850
+ :description => 'Define transactions you want the agent to ignore, by specifying a list of patterns matching the URI you want to ignore. See documentation on (ignoring specific transactions)[https://docs.newrelic.com/docs/agents/ruby-agent/api-guides/ignoring-specific-transactions/#config-ignoring] for more details.'
1837
1851
  },
1838
1852
  :'synthetics.traces_limit' => {
1839
1853
  :default => 20,
@@ -1854,16 +1868,60 @@ module NewRelic
1854
1868
  :public => true,
1855
1869
  :type => Boolean,
1856
1870
  :allowed_from_server => true,
1857
- :description => 'If `true`, the agent captures [New Relic Insights custom events](/docs/insights/new-relic-insights/adding-querying-data/inserting-custom-events-new-relic-apm-agents).'
1871
+ :description => 'If `true`, the agent captures [custom events](/docs/insights/new-relic-insights/adding-querying-data/inserting-custom-events-new-relic-apm-agents).'
1858
1872
  },
1859
1873
  :'custom_insights_events.max_samples_stored' => {
1860
1874
  :default => 1000,
1861
1875
  :public => true,
1862
1876
  :type => Integer,
1863
1877
  :allowed_from_server => true,
1864
- :description => 'Specify a maximum number of custom Insights events to buffer in memory at a time.',
1878
+ :description => 'Defines the maximum number of span events reported from a single harvest. Any Integer between 1 and 10000 is valid.',
1865
1879
  :dynamic_name => true
1866
1880
  },
1881
+ :'application_logging.enabled' => {
1882
+ :default => true,
1883
+ :public => true,
1884
+ :type => Boolean,
1885
+ :allowed_from_server => false,
1886
+ :description => 'If `true`, enables log decoration and the collection of log events and metrics.'
1887
+ },
1888
+ :'application_logging.forwarding.enabled' => {
1889
+ :default => false,
1890
+ :public => true,
1891
+ :type => Boolean,
1892
+ :allowed_from_server => false,
1893
+ :description => 'If `true`, the agent captures log records emitted by your application.'
1894
+ },
1895
+ :'application_logging.forwarding.max_samples_stored' => {
1896
+ :default => 10000,
1897
+ :public => true,
1898
+ :type => Integer,
1899
+ :allowed_from_server => true,
1900
+ :description => 'Defines the maximum number of log records to buffer in memory at a time.',
1901
+ :dynamic_name => true
1902
+ },
1903
+ :'application_logging.metrics.enabled' => {
1904
+ :default => true,
1905
+ :public => true,
1906
+ :type => Boolean,
1907
+ :allowed_from_server => true,
1908
+ :description => 'If `true`, the agent captures metrics related to logging for your application.'
1909
+ },
1910
+ :'application_logging.local_decorating.enabled' => {
1911
+ :default => false,
1912
+ :public => true,
1913
+ :type => Boolean,
1914
+ :allowed_from_server => false,
1915
+ :description => 'If `true`, the agent decorates logs with metadata to link to entities, hosts, traces, and spans.'
1916
+ },
1917
+ :'instrumentation.active_support_logger' => {
1918
+ :default => instrumentation_value_from_boolean(:'application_logging.enabled'),
1919
+ :dynamic_name => true,
1920
+ :public => true,
1921
+ :type => String,
1922
+ :allowed_from_server => false,
1923
+ :description => 'Controls auto-instrumentation of ActiveSupport::Logger at start up. May be one of [auto|prepend|chain|disabled].'
1924
+ },
1867
1925
  :disable_grape_instrumentation => {
1868
1926
  :default => false,
1869
1927
  :public => false,
@@ -2056,7 +2114,7 @@ module NewRelic
2056
2114
  :public => true,
2057
2115
  :type => Boolean,
2058
2116
  :allowed_from_server => false,
2059
- :description => 'If `false`, custom attributes will not be sent on Insights events.'
2117
+ :description => 'If `false`, custom attributes will not be sent on events.'
2060
2118
  },
2061
2119
  :'utilization.detect_aws' => {
2062
2120
  :default => true,
@@ -2155,7 +2213,7 @@ module NewRelic
2155
2213
  :public => false,
2156
2214
  :type => String,
2157
2215
  :allowed_from_server => true,
2158
- :description => 'The account id associated with this application.'
2216
+ :description => 'The account id associated with your application.'
2159
2217
  },
2160
2218
  :primary_application_id => {
2161
2219
  :default => nil,
@@ -2163,7 +2221,7 @@ module NewRelic
2163
2221
  :public => false,
2164
2222
  :type => String,
2165
2223
  :allowed_from_server => true,
2166
- :description => 'The primary id associated with this application.'
2224
+ :description => 'The primary id associated with your application.'
2167
2225
  },
2168
2226
  :'distributed_tracing.enabled' => {
2169
2227
  :default => true,
@@ -11,14 +11,16 @@ module NewRelic
11
11
  EVENT_HARVEST_CONFIG_KEY_MAPPING = {
12
12
  :analytic_event_data => :'transaction_events.max_samples_stored',
13
13
  :custom_event_data => :'custom_insights_events.max_samples_stored',
14
- :error_event_data => :'error_collector.max_event_samples_stored'
14
+ :error_event_data => :'error_collector.max_event_samples_stored',
15
+ :log_event_data => :'application_logging.forwarding.max_samples_stored'
15
16
  }
16
17
 
17
18
  # not including span_event_data here because spans are handled separately in transform_span_event_harvest_config
18
19
  EVENT_HARVEST_EVENT_REPORT_PERIOD_KEY_MAPPING = {
19
20
  :analytic_event_data => :'transaction_event_data',
20
21
  :custom_event_data => :'custom_event_data',
21
- :error_event_data => :'error_event_data'
22
+ :error_event_data => :'error_event_data',
23
+ :log_event_data => :'log_event_data'
22
24
  }
23
25
 
24
26
  def from_config(config)
@@ -79,6 +79,7 @@ module NewRelic
79
79
  :'transaction_events.max_samples_stored' => 'Supportability/EventHarvest/AnalyticEventData/HarvestLimit',
80
80
  :'custom_insights_events.max_samples_stored' => 'Supportability/EventHarvest/CustomEventData/HarvestLimit',
81
81
  :'error_collector.max_event_samples_stored' => 'Supportability/EventHarvest/ErrorEventData/HarvestLimit',
82
+ :'application_logging.forwarding.max_samples_stored' => 'Supportability/EventHarvest/LogEventData/HarvestLimit',
82
83
  :'span_events.max_samples_stored' => 'Supportability/SpanEvent/Limit',
83
84
  :event_report_period => 'Supportability/EventHarvest/ReportPeriod',
84
85
  :'event_report_period.span_event_data' => 'Supportability/SpanEvent/ReportPeriod'
@@ -2,6 +2,7 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
4
  require 'socket'
5
+ require 'new_relic/helper'
5
6
 
6
7
  module NewRelic
7
8
  module Agent
@@ -17,17 +18,22 @@ module NewRelic
17
18
  end
18
19
  end
19
20
 
20
- # calling hostname with -f on some OS's (NetBSD, FreeBSD, Solaris)
21
- # produces invalid option error, but doesn't raise exception. Instead,
22
- # we get back empty string. So, solution here is to check for non-zero
23
- # exit status and retry the command without the -f flag.
21
+ # Pass '-f' to the external executable 'hostname' to request the fully
22
+ # qualified domain name (fqdn). For implementations of 'hostname' that
23
+ # do not support '-f' (such as the one OpenBSD ships with), fall back
24
+ # to calling 'hostname' without the '-f'. If both ways of calling
25
+ # 'hostname' fail, or in a context where 'hostname' is not even
26
+ # available (within an AWS Lambda function, for example), call the
27
+ # 'get' method which uses Socket instead of an external executable.
24
28
  def self.get_fqdn
25
- fqdn = %x(hostname -f 2>/dev/null).chomp!
26
- fqdn = %x(hostname).chomp! unless $?.exitstatus.zero?
27
- fqdn
28
- rescue => e
29
- NewRelic::Agent.logger.debug "Unable to determine fqdn #{e}"
30
- nil
29
+ begin
30
+ NewRelic::Helper.run_command('hostname -f')
31
+ rescue NewRelic::CommandRunFailedError
32
+ NewRelic::Helper.run_command('hostname')
33
+ end
34
+ rescue NewRelic::CommandExecutableNotFoundError, NewRelic::CommandRunFailedError => e
35
+ NewRelic::Agent.logger.debug("#{e.class} - #{e.message}")
36
+ get
31
37
  end
32
38
 
33
39
  def self.heroku_dyno_name_prefix(dyno_name)
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module ActiveSupportLogger
7
+ module Chain
8
+ def instrument!
9
+ ::ActiveSupport::Logger.module_eval do
10
+ include NewRelic::Agent::Instrumentation::ActiveSupportLogger
11
+ def broadcast_with_new_relic(logger)
12
+ broadcast_with_tracing(logger) {
13
+ broadcast_without_newrelic(logger)
14
+ }
15
+ end
16
+
17
+ alias broadcast_without_newrelic broadcast
18
+ alias broadcast broadcast_with_new_relic
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ module ActiveSupportLogger
9
+ # Mark @skip_instrumenting on any broadcasted loggers to instrument Rails.logger only
10
+ def broadcast_with_tracing(logger)
11
+ NewRelic::Agent::Instrumentation::Logger.mark_skip_instrumenting(logger)
12
+ yield
13
+ rescue => error
14
+ NewRelic::Agent.notice_error(error)
15
+ raise
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module ActiveSupportLogger::Prepend
7
+ include NewRelic::Agent::Instrumentation::ActiveSupportLogger
8
+ def broadcast(logger)
9
+ broadcast_with_tracing(logger) { super }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+
5
+ require_relative 'active_support_logger/instrumentation'
6
+ require_relative 'active_support_logger/chain'
7
+ require_relative 'active_support_logger/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :active_support_logger
11
+
12
+ depends_on { defined?(::ActiveSupport::Logger) }
13
+
14
+ executes do
15
+ ::NewRelic::Agent.logger.info 'Installing ActiveSupport::Logger instrumentation'
16
+
17
+ if use_prepend?
18
+ # the only method currently instrumented is a class method
19
+ prepend_instrument ::ActiveSupport::Logger.singleton_class, NewRelic::Agent::Instrumentation::ActiveSupportLogger::Prepend
20
+ else
21
+ chain_instrument NewRelic::Agent::Instrumentation::ActiveSupportLogger::Chain
22
+ end
23
+ end
24
+ end
@@ -51,7 +51,7 @@ module NewRelic::Agent::Instrumentation
51
51
 
52
52
  # Record the HTTP verb for future #perform calls
53
53
  def method_with_newrelic verb
54
- method_with_tracing { method_without_newrelic(verb) }
54
+ method_with_tracing(verb) { method_without_newrelic(verb) }
55
55
  end
56
56
 
57
57
  alias_method :method_without_newrelic, :method
@@ -34,7 +34,7 @@ module NewRelic
34
34
  end
35
35
 
36
36
  def method verb
37
- method_with_tracing { super }
37
+ method_with_tracing(verb) { super }
38
38
  end
39
39
 
40
40
  def header_str
@@ -10,6 +10,17 @@ module NewRelic
10
10
  defined?(@skip_instrumenting) && @skip_instrumenting
11
11
  end
12
12
 
13
+ # We support setting this on loggers which might not have
14
+ # instrumentation installed yet. This lets us disable in AgentLogger
15
+ # and AuditLogger without them having to know the inner details.
16
+ def self.mark_skip_instrumenting(logger)
17
+ logger.instance_variable_set(:@skip_instrumenting, true)
18
+ end
19
+
20
+ def self.clear_skip_instrumenting(logger)
21
+ logger.instance_variable_set(:@skip_instrumenting, false)
22
+ end
23
+
13
24
  def mark_skip_instrumenting
14
25
  @skip_instrumenting = true
15
26
  end
@@ -18,17 +29,8 @@ module NewRelic
18
29
  @skip_instrumenting = false
19
30
  end
20
31
 
21
- LINES = "Logging/lines".freeze
22
- SIZE = "Logging/size".freeze
23
-
24
- def line_metric_name_by_severity(severity)
25
- @line_metrics ||= {}
26
- @line_metrics[severity] ||= "Logging/lines/#{severity}".freeze
27
- end
28
-
29
- def size_metric_name_by_severity(severity)
30
- @size_metrics ||= {}
31
- @size_metrics[severity] ||= "Logging/size/#{severity}".freeze
32
+ def self.enabled?
33
+ NewRelic::Agent.config[:'instrumentation.logger'] != 'disabled'
32
34
  end
33
35
 
34
36
  def format_message_with_tracing(severity, datetime, progname, msg)
@@ -40,14 +42,12 @@ module NewRelic
40
42
  # methods within NewRelic::Agent, or we'll stack overflow!!
41
43
  mark_skip_instrumenting
42
44
 
43
- NewRelic::Agent.increment_metric(LINES)
44
- NewRelic::Agent.increment_metric(line_metric_name_by_severity(severity))
45
-
46
- size = formatted_message.nil? ? 0 : formatted_message.bytesize
47
- NewRelic::Agent.record_metric(SIZE, size)
48
- NewRelic::Agent.record_metric(size_metric_name_by_severity(severity), size)
45
+ unless ::NewRelic::Agent.agent.nil?
46
+ ::NewRelic::Agent.agent.log_event_aggregator.record(formatted_message, severity)
47
+ formatted_message = LocalLogDecorator.decorate(formatted_message)
48
+ end
49
49
 
50
- return formatted_message
50
+ formatted_message
51
51
  ensure
52
52
  clear_skip_instrumenting
53
53
  end
@@ -9,13 +9,14 @@ require_relative 'logger/prepend'
9
9
  DependencyDetection.defer do
10
10
  named :logger
11
11
 
12
- depends_on { defined?(::Logger) }
12
+ depends_on do
13
+ defined?(::Logger) &&
14
+ NewRelic::Agent.config[:'application_logging.enabled']
15
+ end
13
16
 
14
17
  executes do
15
18
  ::NewRelic::Agent.logger.info "Installing Logger instrumentation"
16
- end
17
19
 
18
- executes do
19
20
  if use_prepend?
20
21
  prepend_instrument ::Logger, NewRelic::Agent::Instrumentation::Logger::Prepend
21
22
  else
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+ # frozen_string_literal: true
5
+
6
+ module NewRelic
7
+ module Agent
8
+ #
9
+ # This module contains helper methods related to gathering linking
10
+ # metadata for use with logs in context.
11
+ module LinkingMetadata
12
+ extend self
13
+
14
+ def append_service_linking_metadata metadata
15
+ raise ArgumentError, "Missing argument `metadata`" if metadata.nil?
16
+
17
+ config = ::NewRelic::Agent.config
18
+
19
+ metadata[ENTITY_NAME_KEY] = config[:app_name][0]
20
+ metadata[ENTITY_TYPE_KEY] = ENTITY_TYPE
21
+ metadata[HOSTNAME_KEY] = Hostname.get
22
+
23
+ if entity_guid = config[:entity_guid]
24
+ metadata[ENTITY_GUID_KEY] = entity_guid
25
+ end
26
+
27
+ metadata
28
+ end
29
+
30
+ def append_trace_linking_metadata metadata
31
+ raise ArgumentError, "Missing argument `metadata`" if metadata.nil?
32
+
33
+ if trace_id = Tracer.current_trace_id
34
+ metadata[TRACE_ID_KEY] = trace_id
35
+ end
36
+
37
+ if span_id = Tracer.current_span_id
38
+ metadata[SPAN_ID_KEY] = span_id
39
+ end
40
+
41
+ metadata
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
4
+ # frozen_string_literal: true
5
+
6
+ module NewRelic
7
+ module Agent
8
+ # This module contains helper methods related to decorating log messages
9
+ module LocalLogDecorator
10
+ extend self
11
+
12
+ def decorate(message)
13
+ return message unless decorating_enabled?
14
+
15
+ metadata = NewRelic::Agent.linking_metadata
16
+ formatted_metadata = " NR-LINKING|#{metadata[ENTITY_GUID_KEY]}|#{metadata[HOSTNAME_KEY]}|" \
17
+ "#{metadata[TRACE_ID_KEY]}|#{metadata[SPAN_ID_KEY]}|" \
18
+ "#{escape_entity_name(metadata[ENTITY_NAME_KEY])}|"
19
+
20
+ message.partition("\n").insert(1, formatted_metadata).join
21
+ end
22
+
23
+ private
24
+
25
+ def decorating_enabled?
26
+ NewRelic::Agent.config[:'application_logging.enabled'] &&
27
+ NewRelic::Agent::Instrumentation::Logger.enabled? &&
28
+ NewRelic::Agent.config[:'application_logging.local_decorating.enabled']
29
+ end
30
+
31
+ def escape_entity_name(entity_name)
32
+ return unless entity_name
33
+ URI::DEFAULT_PARSER.escape(entity_name)
34
+ end
35
+ end
36
+ end
37
+ end