module NewRelic::Agent::SpanEventPrimitive

Constants

CATEGORY_KEY
CLIENT
COMPONENT_KEY
DATASTORE_CATEGORY
DB_INSTANCE_KEY
DB_STATEMENT_KEY
DB_STATEMENT_MAX_BYTES
DB_SYSTEM_KEY
DURATION_KEY
ELLIPSIS

Strings for static keys of the event structure

ENTRY_POINT_KEY
EVENT_TYPE

Strings for static values of the event structure

GENERIC_CATEGORY
GUID_KEY
HTTP_CATEGORY
HTTP_METHOD_KEY
HTTP_REQUEST_METHOD_KEY
HTTP_STATUS_CODE_KEY
HTTP_URL_KEY
NAME_KEY
PARENT_ID_KEY
PEER_ADDRESS_KEY
PEER_HOSTNAME_KEY
PRIORITY_KEY
SAMPLED_KEY
SERVER_ADDRESS_KEY
SERVER_PORT_KEY
SPAN_KIND_KEY
TIMESTAMP_KEY
TRACE_ID_KEY
TRACING_VENDORS_KEY
TRANSACTION_ID_KEY
TRANSACTION_NAME_KEY
TRUSTED_PARENT_KEY
TYPE_KEY

Public Instance Methods

error_attributes(segment) click to toggle source

Builds a Hash of error attributes as well as the Span ID when an error is present. Otherwise, returns nil when no error present.

# File lib/new_relic/agent/span_event_primitive.rb, line 59
def error_attributes(segment)
  return if Agent.config[:high_security] || !segment.noticed_error

  segment.noticed_error.build_error_attributes
  segment.noticed_error_attributes
end
for_datastore_segment(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 93
def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize
  intrinsics = intrinsics_for(segment)

  intrinsics[COMPONENT_KEY] = segment.product
  intrinsics[SPAN_KIND_KEY] = CLIENT
  intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY

  agent_attributes = {}

  if segment.database_name && allowed?(DB_INSTANCE_KEY)
    agent_attributes[DB_INSTANCE_KEY] = truncate(segment.database_name)
  end
  if segment.host && segment.port_path_or_id && allowed?(PEER_ADDRESS_KEY)
    agent_attributes[PEER_ADDRESS_KEY] = truncate("#{segment.host}:#{segment.port_path_or_id}")
  end
  if segment.host
    [PEER_HOSTNAME_KEY, SERVER_ADDRESS_KEY].each do |key|
      agent_attributes[key] = truncate(segment.host) if allowed?(key)
    end
  end
  if segment.port_path_or_id&.match?(/^\d+$/) && allowed?(SERVER_PORT_KEY)
    agent_attributes[SERVER_PORT_KEY] = segment.port_path_or_id
  end
  agent_attributes[DB_SYSTEM_KEY] = segment.product if allowed?(DB_SYSTEM_KEY)

  if segment.sql_statement && allowed?(DB_STATEMENT_KEY)
    agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, DB_STATEMENT_MAX_BYTES)
  elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY)
    agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES)
  end

  [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
end
for_external_request_segment(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 73
def for_external_request_segment(segment)
  intrinsics = intrinsics_for(segment)

  intrinsics[COMPONENT_KEY] = segment.library
  intrinsics[HTTP_METHOD_KEY] = segment.procedure
  intrinsics[HTTP_REQUEST_METHOD_KEY] = segment.procedure
  intrinsics[HTTP_STATUS_CODE_KEY] = segment.http_status_code if segment.http_status_code
  intrinsics[CATEGORY_KEY] = HTTP_CATEGORY
  intrinsics[SPAN_KIND_KEY] = CLIENT
  intrinsics[SERVER_ADDRESS_KEY] = segment.uri.host
  intrinsics[SERVER_PORT_KEY] = segment.uri.port
  agent_attributes = {}

  if allowed?(HTTP_URL_KEY)
    agent_attributes[HTTP_URL_KEY] = truncate(segment.uri)
  end

  [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
end
for_segment(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 66
def for_segment(segment)
  intrinsics = intrinsics_for(segment)
  intrinsics[CATEGORY_KEY] = GENERIC_CATEGORY

  [intrinsics, custom_attributes(segment), agent_attributes(segment)]
end

Private Instance Methods

agent_attributes(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 188
def agent_attributes(segment)
  agent_attributes = segment.attributes
    .agent_attributes_for(NewRelic::Agent::AttributeFilter::DST_SPAN_EVENTS)
  error_attributes = error_attributes(segment)
  code_attributes = segment.code_attributes
  agent_attributes = merge_hashes(agent_attributes, error_attributes)
  agent_attributes = merge_hashes(agent_attributes, code_attributes)
  agent_attributes.freeze
end
allowed?(key) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 219
def allowed?(key)
  NewRelic::Agent.instance.attribute_filter.allows_key?(key, AttributeFilter::DST_SPAN_EVENTS)
end
custom_attributes(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 171
def custom_attributes(segment)
  attributes = segment.attributes
  if attributes
    result = attributes.custom_attributes_for(NewRelic::Agent::AttributeFilter::DST_SPAN_EVENTS)
    result.freeze
  else
    NewRelic::EMPTY_HASH
  end
end
intrinsics_for(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 129
def intrinsics_for(segment)
  intrinsics = {
    TYPE_KEY => EVENT_TYPE,
    TRACE_ID_KEY => segment.transaction.trace_id,
    GUID_KEY => segment.guid,
    TRANSACTION_ID_KEY => segment.transaction.guid,
    PRIORITY_KEY => segment.transaction.priority,
    TIMESTAMP_KEY => milliseconds_since_epoch(segment),
    DURATION_KEY => segment.duration,
    NAME_KEY => segment.name
  }

  # with infinite-tracing, transactions may or may not be sampled!
  if segment.transaction.sampled?
    intrinsics[SAMPLED_KEY] = true
  end

  if segment.parent.nil?
    intrinsics[ENTRY_POINT_KEY] = true
    if txn = segment.transaction
      if header_data = txn.distributed_tracer.trace_context_header_data
        if trace_state_vendors = header_data.trace_state_vendors
          intrinsics[TRACING_VENDORS_KEY] = trace_state_vendors unless trace_state_vendors == NewRelic::EMPTY_STR
        end
      end
      if trace_state_payload = txn.distributed_tracer.trace_state_payload
        intrinsics[TRUSTED_PARENT_KEY] = trace_state_payload.id if trace_state_payload.id
      end
    end
  end

  if parent_id = parent_guid(segment)
    intrinsics[PARENT_ID_KEY] = parent_id
  end

  if segment.transaction_name
    intrinsics[TRANSACTION_NAME_KEY] = segment.transaction_name
  end

  intrinsics
end
merge_hashes(hash1, hash2) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 181
def merge_hashes(hash1, hash2)
  return hash1 if hash2.nil? || hash2.empty?
  return hash2 if hash1.nil? || hash1.empty?

  hash1.merge!(hash2)
end
milliseconds_since_epoch(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 206
def milliseconds_since_epoch(segment)
  Integer(segment.start_time.to_f * 1000.0)
end
parent_guid(segment) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 198
def parent_guid(segment)
  if segment.parent
    segment.parent.guid
  elsif txn = segment.transaction
    txn.distributed_tracer.parent_guid
  end
end
truncate(value, max_size = 255) click to toggle source
# File lib/new_relic/agent/span_event_primitive.rb, line 210
def truncate(value, max_size = 255)
  value = value.to_s
  if value.bytesize > max_size
    value.byteslice(0, max_size - 2).chop! << ELLIPSIS
  else
    value
  end
end