class StackifyRubyAPM::Serializers::Transactions

@api private

Public Instance Methods

build_json(config, transaction) click to toggle source

This method will return a Hash object(Transaction). It will accept Config and Transaction instance.

# File lib/stackify_apm/serializers/transactions.rb, line 13
def build_json(config, transaction)
  root_span_json = {
    id: -1,
    call: transaction.name,
    reqBegin: transaction.timestamp,
    reqEnd: transaction.duration,
    props: RootInfo.build(config, transaction),
    exceptions: transaction.exceptions,
    stacks: []
  }

  # serialize all the spans
  children_spans_json = []
  transaction.spans.each do |span|
    children_spans_json.push(build_span(span))
  end

  add_children_spans(root_span_json, children_spans_json)
  root_span_json
rescue StandardError => e
  debug "[Transactions::Serializer] build_json() exception: #{e.inspect}"
end
build_protobuf(config, transaction) click to toggle source

This method will build a Protobuf object. It will accept the Config and Transaction instance. Return a Stackify::Trace object.

# File lib/stackify_apm/serializers/transactions.rb, line 39
def build_protobuf(config, transaction)
  root_span_hash = build_json(config, transaction)
  begin
    # create Trace object
    trace = StackifyProtoBuf::Trace.new
    # create TraceFrame object
    trace_frame = StackifyProtoBuf::TraceFrame.new
    trace_frame.call = root_span_hash[:call].to_s
    trace_frame.start_timestamp_millis = root_span_hash[:reqBegin]
    trace_frame.end_timestamp_millis = root_span_hash[:reqEnd]

    exception = StackifyProtoBuf::TraceException.new
    if root_span_hash[:exceptions].count > 0
      ex = root_span_hash[:exceptions]
      ex.each do |exc|
        exception.caught_by = exc[:CaughtBy].to_s
        exception.exception = exc[:Exception].to_s
        exception.message = exc[:Message].to_s
        exception.timestamp_millis = exc[:Timestamp].to_f
        exc[:Frames].each do |f|
          trace_ex_frame = StackifyProtoBuf::TraceExceptionFrame.new
          trace_ex_frame.method = f[:Method].to_s
          exception.frames.push(trace_ex_frame)
        end
        trace_frame.exceptions.push(exception)
      end
    end

    # create props
    root_frame_props = Google::Protobuf::Map.new(:string, :string)
    root_span_hash[:props].each { |key, value| root_frame_props[key.to_s] = value.to_s }
    trace_frame.properties = root_frame_props

    add_child_frame trace_frame, root_span_hash
    trace.frame = trace_frame
    return trace
  rescue StandardError => e
    debug "[Serializers::Transactions] build_protobuf() exception: #{e.inspect}"
  end
end

Private Instance Methods

add_child_frame(trace_frame, root_span_hash) click to toggle source

It accept StackifyProtoBuf::TraceFrame instance and Root span hash It will create a parent-child structure if there is :stacks found in the current level

# File lib/stackify_apm/serializers/transactions.rb, line 84
def add_child_frame(trace_frame, root_span_hash)
  root_span_hash[:stacks].each do |span|
    child_frame = StackifyProtoBuf::TraceFrame.new
    child_frame.call = span[:call].to_s
    child_frame.start_timestamp_millis = span[:reqBegin]
    child_frame.end_timestamp_millis = span[:reqEnd]

    map_props = Google::Protobuf::Map.new(:string, :string)
    span[:props].each { |key, value| map_props[key.to_s] = value.to_s }
    child_frame.properties = map_props

    trace_frame.frames.push(child_frame)
    if span[:stacks] && span[:stacks].count > 0
      add_child_frame child_frame, span
    end
  end
rescue StandardError => e
  debug "[Serializers::Transactions] add_child_frame() exception: #{e.inspect}"
end
add_children_spans(span_json, children_spans_json) click to toggle source

Add Children Spans to span_json

# File lib/stackify_apm/serializers/transactions.rb, line 105
def add_children_spans(span_json, children_spans_json)
  id = span_json[:id]
  children_spans_json.each do |child_span_json|
    parent_id = child_span_json[:parent_id]

    next unless parent_id == id

    child_span_copy = child_span_json.dup
    add_children_spans(child_span_copy, children_spans_json)
    span_json[:stacks] = [] if span_json[:stacks].nil?
    span_json[:stacks].push(child_span_copy)
  end
end
build_span(span) click to toggle source
# File lib/stackify_apm/serializers/transactions.rb, line 119
def build_span(span)
  span_type = if span.name == 'Custom Instrument'
                "custom.#{span.type}"
              else
                span.type
              end

  span_context = span.context && span.context.to_h

  if span_context && !span_context[:SQL].nil? && span_context[:SQL].length > 100_000
    span_context[:SQL] = span_context[:SQL][0..99_999]
    span_context[:SQL_TRUNCATED] = 'true'
  end

  {
    id: span.id,
    parent_id: span.parent_id,
    call: span_type,
    reqBegin: span.relative_start,
    reqEnd: span.relative_end,
    props: span_context.nil? ? { CATEGORY: 'Ruby' } : span_context,
    stacks: []
  }
end