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,117 +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 'digest'
|
|
6
|
-
require 'json'
|
|
7
|
-
|
|
8
|
-
require 'new_relic/agent/tracer'
|
|
9
|
-
require 'new_relic/agent/threading/agent_thread'
|
|
10
|
-
|
|
11
|
-
module NewRelic
|
|
12
|
-
module Agent
|
|
13
|
-
module DistributedTracing
|
|
14
|
-
class CrossAppMonitor < InboundRequestMonitor
|
|
15
|
-
NEWRELIC_TXN_HEADER = 'X-NewRelic-Transaction'.freeze
|
|
16
|
-
NEWRELIC_APPDATA_HEADER = 'X-NewRelic-App-Data'.freeze
|
|
17
|
-
|
|
18
|
-
NEWRELIC_ID_HEADER_KEY = 'HTTP_X_NEWRELIC_ID'.freeze
|
|
19
|
-
NEWRELIC_TXN_HEADER_KEY = 'HTTP_X_NEWRELIC_TRANSACTION'.freeze
|
|
20
|
-
CONTENT_LENGTH_HEADER_KEY = 'HTTP_CONTENT_LENGTH'.freeze
|
|
21
|
-
|
|
22
|
-
def on_finished_configuring(events)
|
|
23
|
-
if CrossAppTracing.cross_app_enabled?
|
|
24
|
-
Deprecator.deprecate('cross_application_tracer')
|
|
25
|
-
::NewRelic::Agent.logger.warn(
|
|
26
|
-
'[DEPRECATED] Cross application tracing is enabled. Distributed tracing is replacing cross application tracing as the default means of tracing between services. To continue using cross application tracing, enable it with `cross_application_tracer.enabled: true` and `distributed_tracing.enabled: false`'
|
|
27
|
-
)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
register_event_listeners(events)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def path_hash(txn_name, seed)
|
|
34
|
-
rotated = ((seed << 1) | (seed >> 31)) & 0xffffffff
|
|
35
|
-
app_name = NewRelic::Agent.config[:app_name].first
|
|
36
|
-
identifier = "#{app_name};#{txn_name}"
|
|
37
|
-
sprintf('%08x', rotated ^ hash_transaction_name(identifier))
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
# Expected sequence of events:
|
|
43
|
-
# :before_call will save our cross application request id to the thread
|
|
44
|
-
# :after_call will write our response headers/metrics and clean up the thread
|
|
45
|
-
def register_event_listeners(events)
|
|
46
|
-
NewRelic::Agent.logger
|
|
47
|
-
.debug('Wiring up Cross Application Tracing to events after finished configuring')
|
|
48
|
-
|
|
49
|
-
events.subscribe(:before_call) do |env| # THREAD_LOCAL_ACCESS
|
|
50
|
-
if id = decoded_id(env) and should_process_request?(id)
|
|
51
|
-
state = NewRelic::Agent::Tracer.state
|
|
52
|
-
|
|
53
|
-
if (txn = state.current_transaction)
|
|
54
|
-
transaction_info = referring_transaction_info(state, env)
|
|
55
|
-
|
|
56
|
-
payload = CrossAppPayload.new(id, txn, transaction_info)
|
|
57
|
-
txn.distributed_tracer.cross_app_payload = payload
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
CrossAppTracing.assign_intrinsic_transaction_attributes(state)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
events.subscribe(:after_call) do |env, (_status_code, headers, _body)| # THREAD_LOCAL_ACCESS
|
|
65
|
-
state = NewRelic::Agent::Tracer.state
|
|
66
|
-
|
|
67
|
-
insert_response_header(state, env, headers)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def referring_transaction_info(state, request_headers)
|
|
72
|
-
txn_header = request_headers[NEWRELIC_TXN_HEADER_KEY] or return
|
|
73
|
-
deserialize_header(txn_header, NEWRELIC_TXN_HEADER)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def insert_response_header(state, request_headers, response_headers)
|
|
77
|
-
txn = state.current_transaction
|
|
78
|
-
unless txn.nil? || txn.distributed_tracer.cross_app_payload.nil?
|
|
79
|
-
txn.freeze_name_and_execute_if_not_ignored do
|
|
80
|
-
content_length = content_length_from_request(request_headers)
|
|
81
|
-
set_response_headers(txn, response_headers, content_length)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def should_process_request?(id)
|
|
87
|
-
CrossAppTracing.cross_app_enabled? && CrossAppTracing.trusts?(id)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def set_response_headers(transaction, response_headers, content_length)
|
|
91
|
-
payload = obfuscator.obfuscate(
|
|
92
|
-
::JSON.dump(
|
|
93
|
-
transaction.distributed_tracer.cross_app_payload.as_json_array(content_length)
|
|
94
|
-
)
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
response_headers[NEWRELIC_APPDATA_HEADER] = payload
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def decoded_id(request)
|
|
101
|
-
encoded_id = request[NEWRELIC_ID_HEADER_KEY]
|
|
102
|
-
return NewRelic::EMPTY_STR if encoded_id.nil? || encoded_id.empty?
|
|
103
|
-
|
|
104
|
-
obfuscator.deobfuscate(encoded_id)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def content_length_from_request(request)
|
|
108
|
-
request[CONTENT_LENGTH_HEADER_KEY] || -1
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def hash_transaction_name(identifier)
|
|
112
|
-
Digest::MD5.digest(identifier).unpack('@12N').first & 0xffffffff
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
@@ -1,61 +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 NewRelicService
|
|
8
|
-
module SecurityPolicySettings
|
|
9
|
-
EXPECTED_SECURITY_POLICIES = %w[
|
|
10
|
-
record_sql
|
|
11
|
-
attributes_include
|
|
12
|
-
allow_raw_exception_messages
|
|
13
|
-
custom_events
|
|
14
|
-
custom_parameters
|
|
15
|
-
custom_instrumentation_editor
|
|
16
|
-
message_parameters
|
|
17
|
-
].map(&:freeze)
|
|
18
|
-
|
|
19
|
-
def self.preliminary_settings(security_policies)
|
|
20
|
-
enabled_key = 'enabled'.freeze
|
|
21
|
-
settings = EXPECTED_SECURITY_POLICIES.inject({}) do |memo, policy_name|
|
|
22
|
-
memo[policy_name] = {enabled_key => security_policies[policy_name][enabled_key]}
|
|
23
|
-
memo
|
|
24
|
-
end
|
|
25
|
-
{'security_policies' => settings}
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
class Validator
|
|
29
|
-
def initialize(preconnect_response)
|
|
30
|
-
@preconnect_policies = preconnect_response['security_policies'] || {}
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def validate_matching_agent_config!
|
|
34
|
-
agent_keys = EXPECTED_SECURITY_POLICIES
|
|
35
|
-
all_server_keys = @preconnect_policies.keys
|
|
36
|
-
required = 'required'
|
|
37
|
-
required_server_keys = @preconnect_policies.keys.select do |key|
|
|
38
|
-
key if @preconnect_policies[key][required]
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
missing_from_agent = required_server_keys - agent_keys
|
|
42
|
-
unless missing_from_agent.empty?
|
|
43
|
-
message = "The agent received one or more required security policies \
|
|
44
|
-
that it does not recognize and will shut down: #{missing_from_agent.join(',')}. \
|
|
45
|
-
Please check if a newer agent version supports these policies or contact support."
|
|
46
|
-
raise NewRelic::Agent::UnrecoverableAgentException.new(message)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
missing_from_server = agent_keys - all_server_keys
|
|
50
|
-
unless missing_from_server.empty?
|
|
51
|
-
message = "The agent did not receive one or more security policies \
|
|
52
|
-
that it expected and will shut down: #{missing_from_server.join(',')}. Please \
|
|
53
|
-
contact support."
|
|
54
|
-
raise NewRelic::Agent::UnrecoverableAgentException.new(message)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
@@ -1,206 +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
|
-
# This is a class for executing commands related to deployment
|
|
6
|
-
# events. It runs without loading the rails environment
|
|
7
|
-
|
|
8
|
-
require 'yaml'
|
|
9
|
-
require 'net/http'
|
|
10
|
-
require 'new_relic/agent/hostname'
|
|
11
|
-
|
|
12
|
-
# We need to use the Control object but we don't want to load
|
|
13
|
-
# the rails environment. The defined? clause is so that
|
|
14
|
-
# it won't load it twice, something it does when run inside a test
|
|
15
|
-
require 'new_relic/control' unless defined? NewRelic::Control
|
|
16
|
-
|
|
17
|
-
class NewRelic::Cli::Deployments < NewRelic::Cli::Command
|
|
18
|
-
# DEPRECATION NOTICE (Effective September 2025)
|
|
19
|
-
#
|
|
20
|
-
# The entire `NewRelic::Cli::Deployments` class and its associated
|
|
21
|
-
# `newrelic deployments` command are deprecated and will be removed in
|
|
22
|
-
# agent version 10.0.0.
|
|
23
|
-
#
|
|
24
|
-
# Users should migrate to recording deployments directly via New Relic's
|
|
25
|
-
# APIs. For more information, please see the official Change Tracking
|
|
26
|
-
# documentation: https://docs.newrelic.com/docs/change-tracking/change-tracking-introduction/
|
|
27
|
-
#
|
|
28
|
-
# @api public
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
attr_reader :control
|
|
32
|
-
def self.command; 'deployments'; end
|
|
33
|
-
|
|
34
|
-
# Initialize the deployment uploader with command line args.
|
|
35
|
-
# Use -h to see options.
|
|
36
|
-
# When command_line_args is a hash, we are invoking directly and
|
|
37
|
-
# it's treated as an options with optional string values for
|
|
38
|
-
# :user, :description, :appname, :revision, :environment,
|
|
39
|
-
# :license_key, and :changes.
|
|
40
|
-
#
|
|
41
|
-
# Will throw CommandFailed exception if there's any error.
|
|
42
|
-
#
|
|
43
|
-
def initialize(command_line_args)
|
|
44
|
-
@control = NewRelic::Control.instance
|
|
45
|
-
@environment = nil
|
|
46
|
-
@changelog = nil
|
|
47
|
-
@user = nil
|
|
48
|
-
super(command_line_args)
|
|
49
|
-
# needs else branch coverage
|
|
50
|
-
@description ||= @leftover && @leftover.join(' ') # rubocop:disable Style/SafeNavigation
|
|
51
|
-
@user ||= ENV['USER']
|
|
52
|
-
control.env = @environment if @environment
|
|
53
|
-
|
|
54
|
-
load_yaml_from_env(control.env)
|
|
55
|
-
@appname ||= NewRelic::Agent.config[:app_name][0] || control.env || 'development'
|
|
56
|
-
@license_key ||= NewRelic::Agent.config[:license_key]
|
|
57
|
-
@api_key ||= NewRelic::Agent.config[:api_key]
|
|
58
|
-
|
|
59
|
-
setup_logging(control.env)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def load_yaml_from_env(env)
|
|
63
|
-
yaml = NewRelic::Agent::Configuration::YamlSource.new(NewRelic::Agent.config[:config_path], env)
|
|
64
|
-
if yaml.failed?
|
|
65
|
-
messages = yaml.failures.flatten.map(&:to_s).join("\n")
|
|
66
|
-
raise NewRelic::Cli::Command::CommandFailure.new("Error in loading newrelic.yml.\n#{messages}")
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
NewRelic::Agent.config.replace_or_add_config(yaml)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def setup_logging(env)
|
|
73
|
-
NewRelic::Agent.logger = NewRelic::Agent::AgentLogger.new
|
|
74
|
-
NewRelic::Agent.logger.info("Running Capistrano from '#{env}' environment for application '#{@appname}'")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Run the Deployment upload in New Relic via Active Resource.
|
|
78
|
-
# Will possibly print errors and exit the VM
|
|
79
|
-
def run
|
|
80
|
-
msg = <<~TEXT
|
|
81
|
-
DEPRECATED: The `newrelic deployments` command will be removed in v10.0.0. Learn more about the alternate options: https://docs.newrelic.com/docs/change-tracking/change-tracking-introduction/
|
|
82
|
-
TEXT
|
|
83
|
-
NewRelic::Agent.logger.log_once(:warn, 'newrelic_deployments'.to_sym, msg)
|
|
84
|
-
warn msg
|
|
85
|
-
|
|
86
|
-
begin
|
|
87
|
-
@description = nil if @description && @description.strip.empty?
|
|
88
|
-
|
|
89
|
-
if @license_key.nil? || @license_key.empty?
|
|
90
|
-
raise "license_key not set in newrelic.yml for #{control.env}. api_key also required to use New Relic REST API v2"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
if !api_v1? && (@revision.nil? || @revision.empty?)
|
|
94
|
-
raise 'revision required when using New Relic REST API v2 with api_key. Pass in revision using: -r, --revision=REV'
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
request = if api_v1?
|
|
98
|
-
uri = '/deployments.xml'
|
|
99
|
-
create_request(uri, {'x-license-key' => @license_key}, 'application/octet-stream').tap do |req|
|
|
100
|
-
set_params_v1(req)
|
|
101
|
-
end
|
|
102
|
-
else
|
|
103
|
-
uri = "/v2/applications/#{application_id}/deployments.json"
|
|
104
|
-
create_request(uri, {'Api-Key' => @api_key}, 'application/json').tap do |req|
|
|
105
|
-
set_params_v2(req)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
http = ::NewRelic::Agent::NewRelicService.new(nil, control.api_server).http_connection
|
|
110
|
-
response = http.request(request)
|
|
111
|
-
|
|
112
|
-
if response.is_a?(Net::HTTPSuccess)
|
|
113
|
-
info("Recorded deployment to '#{@appname}' (#{@description || Time.now})")
|
|
114
|
-
else
|
|
115
|
-
err_string = REXML::Document.new(response.body).elements['errors/error'].map(&:to_s).join('; ') rescue response.message
|
|
116
|
-
raise NewRelic::Cli::Command::CommandFailure, "Deployment not recorded: #{err_string}"
|
|
117
|
-
end
|
|
118
|
-
rescue SystemCallError, SocketError => e
|
|
119
|
-
# These include Errno connection errors
|
|
120
|
-
err_string = "Transient error attempting to connect to #{control.api_server} (#{e})"
|
|
121
|
-
raise NewRelic::Cli::Command::CommandFailure.new(err_string)
|
|
122
|
-
rescue NewRelic::Cli::Command::CommandFailure
|
|
123
|
-
raise
|
|
124
|
-
rescue => e
|
|
125
|
-
err("Unexpected error attempting to connect to #{control.api_server}")
|
|
126
|
-
info("#{e}: #{e.backtrace.join("\n ")}")
|
|
127
|
-
raise NewRelic::Cli::Command::CommandFailure.new(e.to_s)
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def api_v1?
|
|
132
|
-
@api_key.nil? || @api_key.empty?
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
private
|
|
136
|
-
|
|
137
|
-
def create_request(uri, headers, content_type)
|
|
138
|
-
Net::HTTP::Post.new(uri, headers).tap do |req|
|
|
139
|
-
req.content_type = content_type
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def application_id
|
|
144
|
-
return @application_id if @application_id
|
|
145
|
-
|
|
146
|
-
# Need to connect to collector to acquire application id from the connect response
|
|
147
|
-
# but set monitor_mode false because we don't want to actually report anything
|
|
148
|
-
begin
|
|
149
|
-
NewRelic::Agent.manual_start(monitor_mode: false)
|
|
150
|
-
NewRelic::Agent.agent.connect_to_server
|
|
151
|
-
@application_id = NewRelic::Agent.config[:primary_application_id]
|
|
152
|
-
ensure
|
|
153
|
-
NewRelic::Agent.shutdown
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def set_params_v1(request)
|
|
158
|
-
params = {
|
|
159
|
-
:application_id => @appname,
|
|
160
|
-
:host => NewRelic::Agent::Hostname.get,
|
|
161
|
-
:description => @description,
|
|
162
|
-
:user => @user,
|
|
163
|
-
:revision => @revision,
|
|
164
|
-
:changelog => @changelog
|
|
165
|
-
}.each_with_object({}) do |(k, v), h|
|
|
166
|
-
h["deployment[#{k}]"] = v unless v.nil? || v == ''
|
|
167
|
-
end
|
|
168
|
-
request.set_form_data(params)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def set_params_v2(request)
|
|
172
|
-
request.body = {
|
|
173
|
-
'deployment' => {
|
|
174
|
-
:description => @description,
|
|
175
|
-
:user => @user,
|
|
176
|
-
:revision => @revision,
|
|
177
|
-
:changelog => @changelog
|
|
178
|
-
}
|
|
179
|
-
}.to_json
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def options
|
|
183
|
-
OptionParser.new(%Q(Usage: #{$0} #{self.class.command} [OPTIONS] ["description"] ), 40) do |o|
|
|
184
|
-
o.separator('OPTIONS:')
|
|
185
|
-
o.on('-a', '--appname=NAME', String,
|
|
186
|
-
'Set the application name.',
|
|
187
|
-
'Default is app_name setting in newrelic.yml. Available only when using API v1.') { |e| @appname = e }
|
|
188
|
-
o.on('-i', '--appid=ID', String,
|
|
189
|
-
'Set the application ID',
|
|
190
|
-
'If not provided, will connect to the New Relic collector to get it') { |i| @application_id = i }
|
|
191
|
-
o.on('-e', '--environment=name', String,
|
|
192
|
-
'Override the (RAILS|RUBY|RACK)_ENV setting',
|
|
193
|
-
"currently: #{control.env}") { |e| @environment = e }
|
|
194
|
-
o.on('-u', '--user=USER', String,
|
|
195
|
-
'Specify the user deploying, for information only',
|
|
196
|
-
"Default: #{@user || '<none>'}") { |u| @user = u }
|
|
197
|
-
o.on('-r', '--revision=REV', String,
|
|
198
|
-
'Specify the revision being deployed. Required when using New Relic REST API v2') { |r| @revision = r }
|
|
199
|
-
o.on('-l', '--license-key=KEY', String,
|
|
200
|
-
'Specify the license key of the account for the app being deployed') { |l| @license_key = l }
|
|
201
|
-
o.on('-c', '--changes',
|
|
202
|
-
'Read in a change log from the standard input') { @changelog = STDIN.read }
|
|
203
|
-
yield(o) if block_given?
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
@@ -1,23 +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 'capistrano/framework'
|
|
6
|
-
require_relative 'helpers/send_deployment'
|
|
7
|
-
|
|
8
|
-
namespace :newrelic do
|
|
9
|
-
include SendDeployment
|
|
10
|
-
# notifies New Relic of a deployment
|
|
11
|
-
desc 'Record a deployment in New Relic (newrelic.com)'
|
|
12
|
-
task :notice_deployment do
|
|
13
|
-
if fetch(:newrelic_role)
|
|
14
|
-
on roles(fetch(:newrelic_role)) do
|
|
15
|
-
send_deployment_notification_to_newrelic
|
|
16
|
-
end
|
|
17
|
-
else
|
|
18
|
-
run_locally do
|
|
19
|
-
send_deployment_notification_to_newrelic
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,95 +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
|
-
make_notify_task = proc do
|
|
6
|
-
namespace(:newrelic) do
|
|
7
|
-
# on all deployments, notify New Relic
|
|
8
|
-
desc('Record a deployment in New Relic (newrelic.com)')
|
|
9
|
-
task(:notice_deployment, :roles => :app, :except => {:no_release => true}) do
|
|
10
|
-
rails_env = fetch(:newrelic_rails_env, fetch(:rails_env, 'production'))
|
|
11
|
-
|
|
12
|
-
require 'new_relic/cli/command'
|
|
13
|
-
|
|
14
|
-
begin
|
|
15
|
-
# allow overrides to be defined for revision, description, changelog, appname, and user
|
|
16
|
-
rev = fetch(:newrelic_revision) if exists?(:newrelic_revision)
|
|
17
|
-
description = fetch(:newrelic_desc) if exists?(:newrelic_desc)
|
|
18
|
-
changelog = fetch(:newrelic_changelog) if exists?(:newrelic_changelog)
|
|
19
|
-
appname = fetch(:newrelic_appname) if exists?(:newrelic_appname)
|
|
20
|
-
user = fetch(:newrelic_user) if exists?(:newrelic_user)
|
|
21
|
-
license_key = fetch(:newrelic_license_key) if exists?(:newrelic_license_key)
|
|
22
|
-
|
|
23
|
-
unless scm == :none
|
|
24
|
-
changelog = lookup_changelog(changelog)
|
|
25
|
-
rev = lookup_rev(rev)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
new_revision = rev
|
|
29
|
-
deploy_options = {
|
|
30
|
-
:environment => rails_env,
|
|
31
|
-
:revision => new_revision,
|
|
32
|
-
:changelog => changelog,
|
|
33
|
-
:description => description,
|
|
34
|
-
:appname => appname,
|
|
35
|
-
:user => user,
|
|
36
|
-
:license_key => license_key
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
logger.debug('Uploading deployment to New Relic')
|
|
40
|
-
deployment = NewRelic::Cli::Deployments.new(deploy_options)
|
|
41
|
-
deployment.run
|
|
42
|
-
logger.info('Uploaded deployment information to New Relic')
|
|
43
|
-
rescue NewRelic::Cli::Command::CommandFailure => e
|
|
44
|
-
logger.info(e.message)
|
|
45
|
-
rescue Capistrano::CommandError
|
|
46
|
-
logger.info('Unable to notify New Relic of the deployment... skipping')
|
|
47
|
-
rescue => e
|
|
48
|
-
logger.info("Error creating New Relic deployment (#{e})\n#{e.backtrace.join("\n")}")
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def lookup_changelog(changelog)
|
|
53
|
-
if !changelog
|
|
54
|
-
logger.debug('Getting log of changes for New Relic Deployment details')
|
|
55
|
-
from_revision = source.next_revision(current_revision)
|
|
56
|
-
|
|
57
|
-
if scm == :git
|
|
58
|
-
log_command = "git --no-pager log --no-color --pretty=format:' * %an: %s' " +
|
|
59
|
-
"--abbrev-commit --no-merges #{previous_revision}..#{real_revision}"
|
|
60
|
-
else
|
|
61
|
-
log_command = "#{source.log(from_revision)}"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
changelog = `#{log_command}`
|
|
65
|
-
end
|
|
66
|
-
changelog
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def lookup_rev(rev)
|
|
70
|
-
if rev.nil?
|
|
71
|
-
rev = source.query_revision(source.head()) do |cmd|
|
|
72
|
-
logger.debug("executing locally: '#{cmd}'")
|
|
73
|
-
`#{cmd}`
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
rev = rev[0..6] if scm == :git
|
|
77
|
-
end
|
|
78
|
-
rev
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
require 'capistrano/version'
|
|
84
|
-
|
|
85
|
-
if defined?(Capistrano::Version::MAJOR) && Capistrano::Version::MAJOR < 2
|
|
86
|
-
STDERR.puts "Unable to load #{__FILE__}\nNew Relic Capistrano hooks require at least version 2.0.0"
|
|
87
|
-
else
|
|
88
|
-
instance = Capistrano::Configuration.instance
|
|
89
|
-
|
|
90
|
-
if instance
|
|
91
|
-
instance.load(&make_notify_task)
|
|
92
|
-
else
|
|
93
|
-
make_notify_task.call
|
|
94
|
-
end
|
|
95
|
-
end
|
|
@@ -1,70 +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 SendDeployment
|
|
6
|
-
def send_deployment_notification_to_newrelic
|
|
7
|
-
require 'new_relic/cli/command'
|
|
8
|
-
debug('Uploading deployment to New Relic')
|
|
9
|
-
NewRelic::Cli::Deployments.new(deploy_options).run
|
|
10
|
-
info('Uploaded deployment information to New Relic')
|
|
11
|
-
rescue NewRelic::Cli::Command::CommandFailure => e
|
|
12
|
-
info(e.message)
|
|
13
|
-
rescue => e
|
|
14
|
-
info("Error creating New Relic deployment (#{e})\n#{e.backtrace.join("\n")}")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
def deploy_options
|
|
20
|
-
{
|
|
21
|
-
:environment => fetch_environment,
|
|
22
|
-
:revision => fetch_rev,
|
|
23
|
-
:changelog => fetch_changelog,
|
|
24
|
-
:description => fetch(:newrelic_desc),
|
|
25
|
-
:appname => fetch(:newrelic_appname),
|
|
26
|
-
:user => fetch(:newrelic_user),
|
|
27
|
-
:license_key => fetch(:newrelic_license_key)
|
|
28
|
-
}
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def fetch_changelog
|
|
32
|
-
newrelic_changelog = fetch(:newrelic_changelog)
|
|
33
|
-
has_scm? && !newrelic_changelog ? lookup_changelog : newrelic_changelog
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def fetch_environment
|
|
37
|
-
fetch(:newrelic_rails_env, fetch(:rack_env, fetch(:rails_env, fetch(:stage, 'production'))))
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def fetch_rev
|
|
41
|
-
newrelic_rev = fetch(:newrelic_revision)
|
|
42
|
-
has_scm? && !newrelic_rev ? fetch(:current_revision) : newrelic_rev
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def has_scm?
|
|
46
|
-
has_scm_from_plugin? || has_scm_from_config?
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def has_scm_from_config?
|
|
50
|
-
defined?(scm) && !scm.nil? && scm != :none
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def has_scm_from_plugin?
|
|
54
|
-
respond_to?(:scm_plugin_installed?) && scm_plugin_installed?
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def lookup_changelog
|
|
58
|
-
previous_revision = fetch(:previous_revision)
|
|
59
|
-
current_revision = fetch(:current_revision)
|
|
60
|
-
return unless current_revision && previous_revision
|
|
61
|
-
|
|
62
|
-
debug('Retrieving changelog for New Relic Deployment details')
|
|
63
|
-
|
|
64
|
-
if Rake::Task.task_defined?('git:check')
|
|
65
|
-
log_command = "git --no-pager log --no-color --pretty=format:' * %an: %s' " +
|
|
66
|
-
"--abbrev-commit --no-merges #{previous_revision}..#{current_revision}"
|
|
67
|
-
`#{log_command}`
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
data/lib/new_relic/recipes.rb
DELETED
|
@@ -1,24 +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
|
-
# When installed as a plugin, this is loaded automatically.
|
|
6
|
-
#
|
|
7
|
-
# When installed as a gem, you need to add
|
|
8
|
-
# require 'new_relic/recipes'
|
|
9
|
-
# to deploy.rb
|
|
10
|
-
#
|
|
11
|
-
# Defines newrelic:notice_deployment, which sends information about the deploy
|
|
12
|
-
# to New Relic. The task will run on all app release roles. If it fails, it will
|
|
13
|
-
# not affect the execution of subsequent tasks or cause a rollback.
|
|
14
|
-
#
|
|
15
|
-
# @api public
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
require 'capistrano/version'
|
|
19
|
-
|
|
20
|
-
if defined?(Capistrano::VERSION) && Capistrano::VERSION.to_s.split('.').first.to_i >= 3
|
|
21
|
-
require 'new_relic/recipes/capistrano3'
|
|
22
|
-
else
|
|
23
|
-
require 'new_relic/recipes/capistrano_legacy'
|
|
24
|
-
end
|
data/recipes/newrelic.rb
DELETED
|
@@ -1,10 +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
|
-
# The capistrano recipes in plugins are automatically
|
|
6
|
-
# loaded from here. From gems, they are available from
|
|
7
|
-
# the lib directory. We have to make them available from
|
|
8
|
-
# both locations
|
|
9
|
-
|
|
10
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'new_relic', 'recipes')
|