newrelic_rpm 9.23.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +136 -0
- data/README.md +0 -7
- data/lib/new_relic/agent/agent.rb +9 -4
- data/lib/new_relic/agent/configuration/default_source.rb +103 -181
- data/lib/new_relic/agent/configuration/environment_source.rb +7 -38
- data/lib/new_relic/agent/configuration/manager.rb +141 -59
- data/lib/new_relic/agent/configuration/sampler_config_validator.rb +54 -0
- data/lib/new_relic/agent/configuration/server_source.rb +0 -1
- data/lib/new_relic/agent/connect/response_handler.rb +0 -11
- data/lib/new_relic/agent/datastores.rb +13 -17
- data/lib/new_relic/agent/distributed_tracing.rb +0 -3
- data/lib/new_relic/agent/health_check.rb +1 -0
- data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +2 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -4
- data/lib/new_relic/agent/instrumentation/active_support.rb +8 -1
- data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +22 -14
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +1 -4
- data/lib/new_relic/agent/instrumentation/bunny.rb +0 -1
- data/lib/new_relic/agent/instrumentation/curb/chain.rb +2 -2
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +2 -3
- data/lib/new_relic/agent/instrumentation/curb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
- data/lib/new_relic/agent/instrumentation/excon.rb +2 -3
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -2
- data/lib/new_relic/agent/instrumentation/httpclient.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +0 -2
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +0 -2
- data/lib/new_relic/agent/instrumentation/rack/helpers.rb +1 -3
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -8
- data/lib/new_relic/agent/llm/embedding.rb +1 -8
- data/lib/new_relic/agent/messaging.rb +12 -5
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -2
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +2 -1
- data/lib/new_relic/agent/monitors.rb +0 -3
- data/lib/new_relic/agent/new_relic_service/encoders.rb +0 -14
- data/lib/new_relic/agent/new_relic_service.rb +11 -49
- data/lib/new_relic/agent/opentelemetry/trace/span.rb +41 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +16 -7
- data/lib/new_relic/agent/opentelemetry_bridge.rb +9 -5
- data/lib/new_relic/agent/serverless_handler.rb +2 -2
- data/lib/new_relic/agent/span_event_primitive.rb +1 -1
- data/lib/new_relic/agent/sql_sampler.rb +0 -31
- data/lib/new_relic/agent/stats_engine.rb +1 -0
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +12 -56
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +11 -19
- data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -131
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +0 -2
- data/lib/new_relic/agent/transaction/trace_context.rb +33 -11
- data/lib/new_relic/agent/transaction.rb +35 -4
- data/lib/new_relic/agent/transaction_error_primitive.rb +0 -8
- data/lib/new_relic/agent/transaction_event_primitive.rb +0 -14
- data/lib/new_relic/agent/utilization/gcp.rb +2 -0
- data/lib/new_relic/agent.rb +11 -3
- data/lib/new_relic/cli/command.rb +2 -11
- data/lib/new_relic/control/instance_methods.rb +2 -15
- data/lib/new_relic/control/private_instance_methods.rb +2 -4
- data/lib/new_relic/control/server_methods.rb +0 -6
- data/lib/new_relic/helper.rb +21 -2
- data/lib/new_relic/language_support.rb +3 -34
- data/lib/new_relic/supportability_helper.rb +0 -4
- data/lib/new_relic/version.rb +2 -2
- data/lib/tasks/helpers/newrelicyml.rb +2 -2
- data/lib/tasks/helpers/version_bump.rb +1 -2
- data/newrelic.yml +25 -28
- data/newrelic_rpm.gemspec +10 -9
- metadata +27 -26
- data/bin/newrelic +0 -8
- data/lib/new_relic/agent/configuration/security_policy_source.rb +0 -246
- data/lib/new_relic/agent/distributed_tracing/cross_app_payload.rb +0 -44
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +0 -253
- data/lib/new_relic/agent/external.rb +0 -112
- data/lib/new_relic/agent/monitors/cross_app_monitor.rb +0 -117
- data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +0 -61
- data/lib/new_relic/cli/commands/deployments.rb +0 -206
- data/lib/new_relic/recipes/capistrano3.rb +0 -23
- data/lib/new_relic/recipes/capistrano_legacy.rb +0 -95
- data/lib/new_relic/recipes/helpers/send_deployment.rb +0 -70
- data/lib/new_relic/recipes.rb +0 -24
- data/recipes/newrelic.rb +0 -10
|
@@ -1,246 +0,0 @@
|
|
|
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 'new_relic/agent/configuration/dotted_hash'
|
|
6
|
-
|
|
7
|
-
module NewRelic
|
|
8
|
-
module Agent
|
|
9
|
-
module Configuration
|
|
10
|
-
# The Language Security Policy Source gives customers the ability to
|
|
11
|
-
# configure high security mode settings.
|
|
12
|
-
class SecurityPolicySource < DottedHash
|
|
13
|
-
class << self
|
|
14
|
-
def enabled?(option)
|
|
15
|
-
Agent.config[option]
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def record_sql_enabled?(option)
|
|
19
|
-
Agent.config[option] == 'obfuscated' ||
|
|
20
|
-
Agent.config[option] == 'raw' ||
|
|
21
|
-
false
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def not_empty?(option)
|
|
25
|
-
!Agent.config[option].empty?
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def change_setting(policies, option, new_value)
|
|
29
|
-
current_value = Agent.config[option]
|
|
30
|
-
unless current_value == new_value
|
|
31
|
-
NewRelic::Agent.logger.info( \
|
|
32
|
-
"Setting changed: {#{option}: from #{current_value} " \
|
|
33
|
-
"to #{new_value}}. Source: SecurityPolicySource"
|
|
34
|
-
)
|
|
35
|
-
end
|
|
36
|
-
policies[option] = new_value
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# The keys of the security settings map are the names of security
|
|
41
|
-
# policies received from the server. They map to multiple configuration
|
|
42
|
-
# options in the local config. There is a hash of metadata that
|
|
43
|
-
# corresponds to each configuration option with the following keys:
|
|
44
|
-
#
|
|
45
|
-
# option: the configuration option name
|
|
46
|
-
# supported: true if the agent has one or more corresponding
|
|
47
|
-
# configuration options
|
|
48
|
-
# enabled_fn: a callable that takes the configuration option and returns
|
|
49
|
-
# true if the option is enabled, false otherwise
|
|
50
|
-
# disabled_value: the value of the configuration option when it is
|
|
51
|
-
# disabled
|
|
52
|
-
# permitted_fn: a callable, that will be executed if an option is
|
|
53
|
-
# permitted by the security policy and is also enabled by the config
|
|
54
|
-
|
|
55
|
-
SECURITY_SETTINGS_MAP = {
|
|
56
|
-
'record_sql' => [
|
|
57
|
-
{
|
|
58
|
-
option: :'transaction_tracer.record_sql',
|
|
59
|
-
supported: true,
|
|
60
|
-
enabled_fn: method(:record_sql_enabled?),
|
|
61
|
-
disabled_value: 'off',
|
|
62
|
-
permitted_fn: proc { |policies|
|
|
63
|
-
change_setting(policies, :'transaction_tracer.record_sql', 'obfuscated')
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
option: :'slow_sql.record_sql',
|
|
68
|
-
supported: true,
|
|
69
|
-
enabled_fn: method(:record_sql_enabled?),
|
|
70
|
-
disabled_value: 'off',
|
|
71
|
-
permitted_fn: proc { |policies|
|
|
72
|
-
change_setting(policies, :'slow_sql.record_sql', 'obfuscated')
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
option: :'mongo.capture_queries',
|
|
77
|
-
supported: true,
|
|
78
|
-
enabled_fn: method(:enabled?),
|
|
79
|
-
disabled_value: false,
|
|
80
|
-
permitted_fn: proc { |policies|
|
|
81
|
-
change_setting(policies, :'mongo.obfuscate_queries', true)
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
option: :'elasticsearch.capture_queries',
|
|
86
|
-
supported: true,
|
|
87
|
-
enabled_fn: method(:enabled?),
|
|
88
|
-
disabled_value: false,
|
|
89
|
-
permitted_fn: proc { |policies|
|
|
90
|
-
change_setting(policies, :'elasticsearch.obfuscate_queries', true)
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
option: :'transaction_tracer.record_redis_arguments',
|
|
95
|
-
supported: true,
|
|
96
|
-
enabled_fn: method(:enabled?),
|
|
97
|
-
disabled_value: false,
|
|
98
|
-
permitted_fn: nil
|
|
99
|
-
}
|
|
100
|
-
],
|
|
101
|
-
'attributes_include' => [
|
|
102
|
-
{
|
|
103
|
-
option: :'attributes.include',
|
|
104
|
-
supported: true,
|
|
105
|
-
enabled_fn: method(:not_empty?),
|
|
106
|
-
disabled_value: [],
|
|
107
|
-
permitted_fn: nil
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
option: :'transaction_tracer.attributes.include',
|
|
111
|
-
supported: true,
|
|
112
|
-
enabled_fn: method(:not_empty?),
|
|
113
|
-
disabled_value: [],
|
|
114
|
-
permitted_fn: nil
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
option: :'transaction_events.attributes.include',
|
|
118
|
-
supported: true,
|
|
119
|
-
enabled_fn: method(:not_empty?),
|
|
120
|
-
disabled_value: [],
|
|
121
|
-
permitted_fn: nil
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
option: :'error_collector.attributes.include',
|
|
125
|
-
supported: true,
|
|
126
|
-
enabled_fn: method(:not_empty?),
|
|
127
|
-
disabled_value: [],
|
|
128
|
-
permitted_fn: nil
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
option: :'browser_monitoring.attributes.include',
|
|
132
|
-
supported: true,
|
|
133
|
-
enabled_fn: method(:not_empty?),
|
|
134
|
-
disabled_value: [],
|
|
135
|
-
permitted_fn: nil
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
option: :'span_events.attributes.include',
|
|
139
|
-
supported: true,
|
|
140
|
-
enabled_fn: method(:not_empty?),
|
|
141
|
-
disabled_value: [],
|
|
142
|
-
permitted_fn: nil
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
option: :'transaction_segments.attributes.include',
|
|
146
|
-
supported: true,
|
|
147
|
-
enabled_fn: method(:not_empty?),
|
|
148
|
-
disabled_value: [],
|
|
149
|
-
permitted_fn: nil
|
|
150
|
-
}
|
|
151
|
-
],
|
|
152
|
-
'ai_monitoring' => [
|
|
153
|
-
{
|
|
154
|
-
option: :'ai_monitoring.enabled',
|
|
155
|
-
supported: true,
|
|
156
|
-
enabled_fn: method(:enabled?),
|
|
157
|
-
disabled_value: false,
|
|
158
|
-
permitted_fn: nil
|
|
159
|
-
}
|
|
160
|
-
],
|
|
161
|
-
'allow_raw_exception_messages' => [
|
|
162
|
-
{
|
|
163
|
-
option: :'strip_exception_messages.enabled',
|
|
164
|
-
supported: true,
|
|
165
|
-
enabled_fn: method(:enabled?),
|
|
166
|
-
disabled_value: false,
|
|
167
|
-
permitted_fn: nil
|
|
168
|
-
}
|
|
169
|
-
],
|
|
170
|
-
'custom_events' => [
|
|
171
|
-
{
|
|
172
|
-
option: :'custom_insights_events.enabled',
|
|
173
|
-
supported: true,
|
|
174
|
-
enabled_fn: method(:enabled?),
|
|
175
|
-
disabled_value: false,
|
|
176
|
-
permitted_fn: nil
|
|
177
|
-
}
|
|
178
|
-
],
|
|
179
|
-
'custom_parameters' => [
|
|
180
|
-
{
|
|
181
|
-
option: :'custom_attributes.enabled',
|
|
182
|
-
supported: true,
|
|
183
|
-
enabled_fn: method(:enabled?),
|
|
184
|
-
disabled_value: false,
|
|
185
|
-
permitted_fn: nil
|
|
186
|
-
}
|
|
187
|
-
],
|
|
188
|
-
'custom_instrumentation_editor' => [
|
|
189
|
-
{
|
|
190
|
-
option: nil,
|
|
191
|
-
supported: false,
|
|
192
|
-
enabled_fn: nil,
|
|
193
|
-
disabled_value: nil,
|
|
194
|
-
permitted_fn: nil
|
|
195
|
-
}
|
|
196
|
-
],
|
|
197
|
-
'message_parameters' => [
|
|
198
|
-
{
|
|
199
|
-
option: :'message_tracer.segment_parameters.enabled',
|
|
200
|
-
supported: true,
|
|
201
|
-
enabled_fn: method(:enabled?),
|
|
202
|
-
disabled_value: false,
|
|
203
|
-
permitted_fn: nil
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
def initialize(security_policies)
|
|
209
|
-
super(build_overrides(security_policies))
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
ENABLED = 'enabled'.freeze
|
|
213
|
-
COLON_COLON = '::'.freeze
|
|
214
|
-
|
|
215
|
-
def build_overrides(security_policies)
|
|
216
|
-
security_policies.inject({}) do |settings, (policy_name, policy_settings)|
|
|
217
|
-
SECURITY_SETTINGS_MAP[policy_name].each do |policy|
|
|
218
|
-
next unless policy[:supported]
|
|
219
|
-
|
|
220
|
-
if policy_settings[ENABLED]
|
|
221
|
-
if policy[:enabled_fn].call(policy[:option])
|
|
222
|
-
if permitted_fn = policy[:permitted_fn]
|
|
223
|
-
permitted_fn.call(settings)
|
|
224
|
-
end
|
|
225
|
-
else
|
|
226
|
-
config_source = Agent.config.source(policy[:option]).class.name.split(COLON_COLON).last
|
|
227
|
-
NewRelic::Agent.logger.info( \
|
|
228
|
-
"Setting applied: {#{policy[:option]}: #{policy[:disabled_value]}}. " \
|
|
229
|
-
"Source: #{config_source}"
|
|
230
|
-
)
|
|
231
|
-
end
|
|
232
|
-
else
|
|
233
|
-
settings[policy[:option]] = policy[:disabled_value]
|
|
234
|
-
NewRelic::Agent.logger.info( \
|
|
235
|
-
"Setting applied: {#{policy[:option]}: #{policy[:disabled_value]}}. " \
|
|
236
|
-
'Source: SecurityPolicySource'
|
|
237
|
-
)
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
settings
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
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
|
|
6
|
-
module Agent
|
|
7
|
-
class CrossAppPayload
|
|
8
|
-
attr_reader :id, :transaction, :referring_guid, :referring_trip_id, :referring_path_hash
|
|
9
|
-
|
|
10
|
-
def initialize(id, transaction, transaction_info)
|
|
11
|
-
@id = id
|
|
12
|
-
@transaction = transaction
|
|
13
|
-
|
|
14
|
-
transaction_info ||= []
|
|
15
|
-
@referring_guid = transaction_info[0]
|
|
16
|
-
# unused_flag = transaction_info[1]
|
|
17
|
-
@referring_trip_id = string_or_false_for(transaction_info[2])
|
|
18
|
-
@referring_path_hash = string_or_false_for(transaction_info[3])
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def as_json_array(content_length)
|
|
22
|
-
queue_time_in_seconds = [transaction.queue_time, 0.0].max
|
|
23
|
-
start_time_in_seconds = [transaction.start_time, 0.0].max
|
|
24
|
-
app_time_in_seconds = Process.clock_gettime(Process::CLOCK_REALTIME) - start_time_in_seconds
|
|
25
|
-
|
|
26
|
-
[
|
|
27
|
-
NewRelic::Agent.config[:cross_process_id],
|
|
28
|
-
transaction.best_name,
|
|
29
|
-
queue_time_in_seconds,
|
|
30
|
-
app_time_in_seconds,
|
|
31
|
-
content_length,
|
|
32
|
-
transaction.guid,
|
|
33
|
-
false
|
|
34
|
-
]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def string_or_false_for(value)
|
|
40
|
-
value.is_a?(String) && value
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,253 +0,0 @@
|
|
|
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 'json'
|
|
6
|
-
|
|
7
|
-
module NewRelic
|
|
8
|
-
module Agent
|
|
9
|
-
module CrossAppTracing
|
|
10
|
-
# The cross app response header for "outgoing" calls
|
|
11
|
-
NR_APPDATA_HEADER = 'X-NewRelic-App-Data'
|
|
12
|
-
|
|
13
|
-
# The cross app id header for "outgoing" calls
|
|
14
|
-
NR_ID_HEADER = 'X-NewRelic-ID'
|
|
15
|
-
|
|
16
|
-
# The cross app transaction header for "outgoing" calls
|
|
17
|
-
NR_TXN_HEADER = 'X-NewRelic-Transaction'
|
|
18
|
-
|
|
19
|
-
NR_MESSAGE_BROKER_ID_HEADER = 'NewRelicID'
|
|
20
|
-
NR_MESSAGE_BROKER_TXN_HEADER = 'NewRelicTransaction'
|
|
21
|
-
NR_MESSAGE_BROKER_SYNTHETICS_HEADER = 'NewRelicSynthetics'
|
|
22
|
-
|
|
23
|
-
attr_accessor :is_cross_app_caller, :cross_app_payload, :cat_path_hashes
|
|
24
|
-
|
|
25
|
-
def is_cross_app_caller?
|
|
26
|
-
@is_cross_app_caller ||= false
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def is_cross_app_callee?
|
|
30
|
-
!cross_app_payload.nil?
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def is_cross_app?
|
|
34
|
-
is_cross_app_caller? || is_cross_app_callee?
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def cat_trip_id
|
|
38
|
-
cross_app_payload&.referring_trip_id || transaction.guid
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def cross_app_monitor
|
|
42
|
-
NewRelic::Agent.instance.monitors.cross_app_monitor
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def cat_path_hash
|
|
46
|
-
referring_path_hash = cat_referring_path_hash || '0'
|
|
47
|
-
seed = referring_path_hash.to_i(16)
|
|
48
|
-
result = cross_app_monitor.path_hash(transaction.best_name, seed)
|
|
49
|
-
record_cat_path_hash(result)
|
|
50
|
-
result
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def insert_cross_app_header(headers)
|
|
54
|
-
return unless CrossAppTracing.cross_app_enabled?
|
|
55
|
-
|
|
56
|
-
@is_cross_app_caller = true
|
|
57
|
-
txn_guid = transaction.guid
|
|
58
|
-
trip_id = cat_trip_id
|
|
59
|
-
path_hash = cat_path_hash
|
|
60
|
-
|
|
61
|
-
insert_request_headers(headers, txn_guid, trip_id, path_hash)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def add_message_cat_headers(headers)
|
|
65
|
-
return unless CrossAppTracing.cross_app_enabled?
|
|
66
|
-
|
|
67
|
-
@is_cross_app_caller = true
|
|
68
|
-
insert_message_headers(headers,
|
|
69
|
-
transaction.guid,
|
|
70
|
-
cat_trip_id,
|
|
71
|
-
cat_path_hash,
|
|
72
|
-
transaction.raw_synthetics_header)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def record_cross_app_metrics
|
|
76
|
-
if (id = cross_app_payload&.id)
|
|
77
|
-
app_time_in_seconds = [
|
|
78
|
-
Process.clock_gettime(Process::CLOCK_REALTIME) - transaction.start_time,
|
|
79
|
-
0.0
|
|
80
|
-
].max
|
|
81
|
-
NewRelic::Agent.record_metric("ClientApplication/#{id}/all", app_time_in_seconds)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def assign_cross_app_intrinsics
|
|
86
|
-
transaction.attributes.add_intrinsic_attribute(:trip_id, cat_trip_id)
|
|
87
|
-
transaction.attributes.add_intrinsic_attribute(:path_hash, cat_path_hash)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
private
|
|
91
|
-
|
|
92
|
-
def insert_message_headers(headers, txn_guid, trip_id, path_hash, synthetics_header)
|
|
93
|
-
headers[NR_MESSAGE_BROKER_ID_HEADER] = obfuscator.obfuscate(Agent.config[:cross_process_id])
|
|
94
|
-
headers[NR_MESSAGE_BROKER_TXN_HEADER] = obfuscator.obfuscate(::JSON.dump([txn_guid, false, trip_id, path_hash]))
|
|
95
|
-
headers[NR_MESSAGE_BROKER_SYNTHETICS_HEADER] = synthetics_header if synthetics_header
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def record_cat_path_hash(hash)
|
|
99
|
-
@cat_path_hashes ||= []
|
|
100
|
-
if @cat_path_hashes.size < 10 && !@cat_path_hashes.include?(hash)
|
|
101
|
-
@cat_path_hashes << hash
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def cat_referring_path_hash
|
|
106
|
-
cross_app_payload&.referring_path_hash
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def append_cat_info(payload)
|
|
110
|
-
if (referring_guid = cross_app_payload&.referring_guid)
|
|
111
|
-
payload[:referring_transaction_guid] = referring_guid
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
return unless transaction.include_guid?
|
|
115
|
-
|
|
116
|
-
payload[:guid] = transaction.guid
|
|
117
|
-
|
|
118
|
-
return unless is_cross_app?
|
|
119
|
-
|
|
120
|
-
trip_id = cat_trip_id
|
|
121
|
-
path_hash = cat_path_hash
|
|
122
|
-
referring_path_hash = cat_referring_path_hash
|
|
123
|
-
|
|
124
|
-
payload[:cat_trip_id] = trip_id if trip_id
|
|
125
|
-
payload[:cat_referring_path_hash] = referring_path_hash if referring_path_hash
|
|
126
|
-
|
|
127
|
-
if path_hash
|
|
128
|
-
payload[:cat_path_hash] = path_hash
|
|
129
|
-
|
|
130
|
-
alternate_path_hashes = cat_path_hashes - [path_hash]
|
|
131
|
-
unless alternate_path_hashes.empty?
|
|
132
|
-
payload[:cat_alternate_path_hashes] = alternate_path_hashes
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
###############
|
|
138
|
-
module_function
|
|
139
|
-
|
|
140
|
-
###############
|
|
141
|
-
|
|
142
|
-
def cross_app_enabled?
|
|
143
|
-
valid_cross_process_id? &&
|
|
144
|
-
valid_encoding_key? &&
|
|
145
|
-
cross_application_tracer_enabled?
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def valid_cross_process_id?
|
|
149
|
-
if Agent.config[:cross_process_id] && Agent.config[:cross_process_id].length > 0
|
|
150
|
-
true
|
|
151
|
-
else
|
|
152
|
-
NewRelic::Agent.logger.debug('No cross_process_id configured')
|
|
153
|
-
false
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def valid_encoding_key?
|
|
158
|
-
if Agent.config[:encoding_key] && Agent.config[:encoding_key].length > 0
|
|
159
|
-
true
|
|
160
|
-
else
|
|
161
|
-
NewRelic::Agent.logger.debug('No encoding_key set')
|
|
162
|
-
false
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def cross_application_tracer_enabled?
|
|
167
|
-
!NewRelic::Agent.config[:"distributed_tracing.enabled"] &&
|
|
168
|
-
NewRelic::Agent.config[:"cross_application_tracer.enabled"]
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def obfuscator
|
|
172
|
-
@obfuscator ||= NewRelic::Agent::Obfuscator.new(Agent.config[:encoding_key])
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def insert_request_headers(request, txn_guid, trip_id, path_hash)
|
|
176
|
-
cross_app_id = NewRelic::Agent.config[:cross_process_id]
|
|
177
|
-
txn_data = ::JSON.dump([txn_guid, false, trip_id, path_hash])
|
|
178
|
-
|
|
179
|
-
request[NR_ID_HEADER] = obfuscator.obfuscate(cross_app_id)
|
|
180
|
-
request[NR_TXN_HEADER] = obfuscator.obfuscate(txn_data)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def response_has_crossapp_header?(response)
|
|
184
|
-
if !!response[NR_APPDATA_HEADER]
|
|
185
|
-
true
|
|
186
|
-
else
|
|
187
|
-
NewRelic::Agent.logger.debug("No #{NR_APPDATA_HEADER} header")
|
|
188
|
-
false
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Extract x-process application data from the specified +response+ and return
|
|
193
|
-
# it as an array of the form:
|
|
194
|
-
#
|
|
195
|
-
# [
|
|
196
|
-
# <cross app ID>,
|
|
197
|
-
# <transaction name>,
|
|
198
|
-
# <queue time in seconds>,
|
|
199
|
-
# <response time in seconds>,
|
|
200
|
-
# <request content length in bytes>,
|
|
201
|
-
# <transaction GUID>
|
|
202
|
-
# ]
|
|
203
|
-
def extract_appdata(response)
|
|
204
|
-
appdata = response[NR_APPDATA_HEADER]
|
|
205
|
-
|
|
206
|
-
decoded_appdata = obfuscator.deobfuscate(appdata)
|
|
207
|
-
decoded_appdata.set_encoding(::Encoding::UTF_8) if
|
|
208
|
-
decoded_appdata.respond_to?(:set_encoding)
|
|
209
|
-
|
|
210
|
-
::JSON.parse(decoded_appdata)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def valid_cross_app_id?(xp_id)
|
|
214
|
-
!!(xp_id =~ /\A\d+#\d+\z/)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def message_has_crossapp_request_header?(headers)
|
|
218
|
-
!!headers[NR_MESSAGE_BROKER_ID_HEADER]
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def reject_messaging_cat_headers(headers)
|
|
222
|
-
headers.reject { |k, _| k == NR_MESSAGE_BROKER_ID_HEADER || k == NR_MESSAGE_BROKER_TXN_HEADER }
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def trusts?(id)
|
|
226
|
-
split_id = id.match(/(\d+)#\d+/)
|
|
227
|
-
return false if split_id.nil?
|
|
228
|
-
|
|
229
|
-
NewRelic::Agent.config[:trusted_account_ids].include?(split_id.captures.first.to_i)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def trusted_valid_cross_app_id?(id)
|
|
233
|
-
valid_cross_app_id?(id) && trusts?(id)
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# From inbound request headers
|
|
237
|
-
def assign_intrinsic_transaction_attributes(state)
|
|
238
|
-
# We expect to get the before call to set the id (if we have it) before
|
|
239
|
-
# this, and then write our custom parameter when the transaction starts
|
|
240
|
-
return unless (txn = state.current_transaction)
|
|
241
|
-
return unless (payload = txn.distributed_tracer.cross_app_payload)
|
|
242
|
-
|
|
243
|
-
if (cross_app_id = payload.id)
|
|
244
|
-
txn.attributes.add_intrinsic_attribute(:client_cross_process_id, cross_app_id)
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
if (referring_guid = payload.referring_guid)
|
|
248
|
-
txn.attributes.add_intrinsic_attribute(:referring_transaction_guid, referring_guid)
|
|
249
|
-
end
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
@@ -1,112 +0,0 @@
|
|
|
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 'new_relic/agent/transaction/tracing'
|
|
6
|
-
require 'new_relic/agent/distributed_tracing/cross_app_tracing'
|
|
7
|
-
require 'new_relic/agent/distributed_tracing/cross_app_payload'
|
|
8
|
-
|
|
9
|
-
module NewRelic
|
|
10
|
-
module Agent
|
|
11
|
-
#
|
|
12
|
-
# This module contains helper methods to facilitate
|
|
13
|
-
# instrumentation of external requests not directly supported by
|
|
14
|
-
# the Ruby agent. It is intended to be primarily used by authors
|
|
15
|
-
# of 3rd-party instrumentation.
|
|
16
|
-
#
|
|
17
|
-
# @api public
|
|
18
|
-
module External
|
|
19
|
-
extend self
|
|
20
|
-
|
|
21
|
-
NON_HTTP_CAT_ID_HEADER = 'NewRelicID'.freeze
|
|
22
|
-
NON_HTTP_CAT_TXN_HEADER = 'NewRelicTransaction'.freeze
|
|
23
|
-
NON_HTTP_CAT_SYNTHETICS_HEADER = 'NewRelicSynthetics'.freeze
|
|
24
|
-
NON_HTTP_CAT_CONTENT_LENGTH = -1
|
|
25
|
-
|
|
26
|
-
# Process obfuscated +String+ identifying a calling application and transaction that is also running a
|
|
27
|
-
# New Relic agent and save information in current transaction for inclusion in a trace. The +String+ is
|
|
28
|
-
# generated by +get_request_metadata+ on the calling application.
|
|
29
|
-
#
|
|
30
|
-
# @param request_metadata [String] received obfuscated request metadata
|
|
31
|
-
#
|
|
32
|
-
# @!scope class
|
|
33
|
-
# @api public
|
|
34
|
-
#
|
|
35
|
-
def process_request_metadata(request_metadata)
|
|
36
|
-
NewRelic::Agent.record_api_supportability_metric(:process_request_metadata)
|
|
37
|
-
return unless CrossAppTracing.cross_app_enabled?
|
|
38
|
-
|
|
39
|
-
state = NewRelic::Agent::Tracer.state
|
|
40
|
-
if transaction = state.current_transaction
|
|
41
|
-
rmd = ::JSON.parse(obfuscator.deobfuscate(request_metadata))
|
|
42
|
-
|
|
43
|
-
# handle/check ID
|
|
44
|
-
#
|
|
45
|
-
if id = rmd[NON_HTTP_CAT_ID_HEADER] and CrossAppTracing.trusted_valid_cross_app_id?(id)
|
|
46
|
-
# handle transaction info
|
|
47
|
-
#
|
|
48
|
-
if txn_info = rmd[NON_HTTP_CAT_TXN_HEADER]
|
|
49
|
-
payload = CrossAppPayload.new(id, transaction, txn_info)
|
|
50
|
-
transaction.distributed_tracer.cross_app_payload = payload
|
|
51
|
-
|
|
52
|
-
CrossAppTracing.assign_intrinsic_transaction_attributes(state)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# handle synthetics
|
|
56
|
-
#
|
|
57
|
-
if synth = rmd[NON_HTTP_CAT_SYNTHETICS_HEADER]
|
|
58
|
-
transaction.synthetics_payload = synth
|
|
59
|
-
transaction.raw_synthetics_header = obfuscator.obfuscate(::JSON.dump(synth))
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
else
|
|
63
|
-
NewRelic::Agent.logger.error("error processing request metadata: invalid/non-trusted ID: '#{id}'")
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
nil
|
|
67
|
-
end
|
|
68
|
-
rescue => e
|
|
69
|
-
NewRelic::Agent.logger.error('error during process_request_metadata', e)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Obtain an obfuscated +String+ suitable for delivery across public networks that carries transaction
|
|
73
|
-
# information from this application to a calling application which is also running a New Relic agent.
|
|
74
|
-
# This +String+ can be processed by +process_response_metadata+ on the calling application.
|
|
75
|
-
#
|
|
76
|
-
# @return [String] obfuscated response metadata to send
|
|
77
|
-
#
|
|
78
|
-
# @!scope class
|
|
79
|
-
# @api public
|
|
80
|
-
#
|
|
81
|
-
def get_response_metadata
|
|
82
|
-
NewRelic::Agent.record_api_supportability_metric(:get_response_metadata)
|
|
83
|
-
return unless CrossAppTracing.cross_app_enabled?
|
|
84
|
-
|
|
85
|
-
return unless (txn = Tracer.current_transaction)
|
|
86
|
-
return unless (payload = txn.distributed_tracer.cross_app_payload)
|
|
87
|
-
|
|
88
|
-
# must freeze the name since we're responding with it
|
|
89
|
-
#
|
|
90
|
-
txn.freeze_name_and_execute_if_not_ignored do
|
|
91
|
-
# build response payload
|
|
92
|
-
#
|
|
93
|
-
rmd = {
|
|
94
|
-
NewRelicAppData: payload.as_json_array(NON_HTTP_CAT_CONTENT_LENGTH)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
# obfuscate the generated response metadata JSON
|
|
98
|
-
#
|
|
99
|
-
obfuscator.obfuscate(::JSON.dump(rmd))
|
|
100
|
-
end
|
|
101
|
-
rescue => e
|
|
102
|
-
NewRelic::Agent.logger.error('error during get_response_metadata', e)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
private
|
|
106
|
-
|
|
107
|
-
def obfuscator
|
|
108
|
-
CrossAppTracing.obfuscator
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|