module NewRelic::Agent::External

This module contains helper methods to facilitate instrumentation of external requests not directly supported by the Ruby agent. It is intended to be primarily used by authors of 3rd-party instrumentation.

@api public

Constants

NON_HTTP_CAT_CONTENT_LENGTH
NON_HTTP_CAT_ID_HEADER
NON_HTTP_CAT_SYNTHETICS_HEADER
NON_HTTP_CAT_TXN_HEADER

Public Instance Methods

get_response_metadata() click to toggle source

Obtain an obfuscated String suitable for delivery across public networks that carries transaction information from this application to a calling application which is also running a New Relic agent. This String can be processed by process_response_metadata on the calling application.

@return [String] obfuscated response metadata to send

@api public

# File lib/new_relic/agent/external.rb, line 79
def get_response_metadata
  NewRelic::Agent.record_api_supportability_metric(:get_response_metadata)
  return unless CrossAppTracing.cross_app_enabled?

  return unless (txn = Tracer.current_transaction)
  return unless (payload = txn.distributed_tracer.cross_app_payload)

  # must freeze the name since we're responding with it
  #
  txn.freeze_name_and_execute_if_not_ignored do
    # build response payload
    #
    rmd = {
      NewRelicAppData: payload.as_json_array(NON_HTTP_CAT_CONTENT_LENGTH)
    }

    # obfuscate the generated response metadata JSON
    #
    obfuscator.obfuscate(::JSON.dump(rmd))
  end
rescue => e
  NewRelic::Agent.logger.error('error during get_response_metadata', e)
end
process_request_metadata(request_metadata) click to toggle source

Process obfuscated String identifying a calling application and transaction that is also running a New Relic agent and save information in current transaction for inclusion in a trace. The String is generated by get_request_metadata on the calling application.

@param request_metadata [String] received obfuscated request metadata

@api public

# File lib/new_relic/agent/external.rb, line 34
def process_request_metadata(request_metadata)
  NewRelic::Agent.record_api_supportability_metric(:process_request_metadata)
  return unless CrossAppTracing.cross_app_enabled?

  state = NewRelic::Agent::Tracer.state
  if transaction = state.current_transaction
    rmd = ::JSON.parse(obfuscator.deobfuscate(request_metadata))

    # handle/check ID
    #
    if id = rmd[NON_HTTP_CAT_ID_HEADER] and CrossAppTracing.trusted_valid_cross_app_id?(id)
      # handle transaction info
      #
      if txn_info = rmd[NON_HTTP_CAT_TXN_HEADER]
        payload = CrossAppPayload.new(id, transaction, txn_info)
        transaction.distributed_tracer.cross_app_payload = payload

        CrossAppTracing.assign_intrinsic_transaction_attributes(state)
      end

      # handle synthetics
      #
      if synth = rmd[NON_HTTP_CAT_SYNTHETICS_HEADER]
        transaction.synthetics_payload = synth
        transaction.raw_synthetics_header = obfuscator.obfuscate(::JSON.dump(synth))
      end

    else
      NewRelic::Agent.logger.error("error processing request metadata: invalid/non-trusted ID: '#{id}'")
    end

    nil
  end
rescue => e
  NewRelic::Agent.logger.error('error during process_request_metadata', e)
end

Private Instance Methods

obfuscator() click to toggle source
# File lib/new_relic/agent/external.rb, line 105
def obfuscator
  CrossAppTracing.obfuscator
end