Module: TingYun::Agent::CrossAppTracing

Extended by:
Instrumentation::Support::ExternalError
Defined in:
lib/ting_yun/agent/cross_app/cross_app_tracing.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

TY_ID_HEADER =

The cross app id header for “outgoing” calls

'X-Tingyun-Id'.freeze
TY_DATA_HEADER =
'X-Tingyun-Tx-Data'.freeze

Class Method Summary collapse

Methods included from Instrumentation::Support::ExternalError

capture_exception, handle_error, set_attributes

Class Method Details

.add_transaction_trace_info(request, response, cross_app, tx_data) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 93

def add_transaction_trace_info(request, response, cross_app, tx_data)
  state = TingYun::Agent::TransactionState.tl_get
  ::TingYun::Agent::Collector::TransactionSampler.add_node_info(:uri => TingYun::Agent::HTTPClients::URIUtil.filter_uri(request.uri))
  if cross_app
    ::TingYun::Agent::Collector::TransactionSampler.tl_builder.set_txId_and_txData(state.client_transaction_id || state.request_guid, tx_data)
  end
end

.cross_app_enabled?Boolean

Returns:

  • (Boolean)


122
123
124
125
126
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 122

def cross_app_enabled?
  TingYun::Agent.config[:tingyunIdSecret] && TingYun::Agent.config[:tingyunIdSecret].size > 0 &&
      TingYun::Agent.config[:'nbs.action_tracer.enabled'] &&
      TingYun::Agent.config[:'nbs.transaction_tracer.enabled']
end

.finish_trace(state, t0, node, request, response) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 53

def finish_trace(state, t0, node, request, response)

  t1 = Time.now.to_f
  duration = (t1- t0) * 1000
  state.timings.external_duration = duration

  begin
    if request
      cross_app = response_is_cross_app?(response)

      metrics = metrics_for(request)
      node_name = metrics.pop
      tx_data = TingYun::Support::Serialize::JSONWrapper.load(get_ty_data_header(response).gsub("'",'"')) || {}
      # net_block_duration = tx_data["time"]? duration - tx_data["time"]["duration"]- tx_data["time"]["qu"] : duration
      # net_block_duration = duration if net_block_duration < 0
      ::TingYun::Agent.instance.stats_engine.record_scoped_and_unscoped_metrics(state, node_name, metrics, duration)
      if cross_app
        _duration =  tx_data["time"]["duration"] + tx_data["time"]["qu"] + 0.1
        metrics_cross_app = metrics_for_cross_app(request, response)
        txn = state.current_transaction
        txn.metrics.record_scoped(metrics_cross_app.pop, duration, _duration)
        txn.metrics.record_unscoped(metrics_cross_app, _duration)
      end

      if node
        node.name = node_name
        add_transaction_trace_info(request, response, cross_app, tx_data)
      end
    end
  rescue => err
    TingYun::Agent.logger.error "Uncaught exception while finishing an HTTP request trace", err
  ensure
    if node
      stack = state.traced_method_stack
      stack.pop_frame(state, node, node_name, t1)
    end
  end
end

.get_ty_data_header(response) ⇒ Object



147
148
149
150
151
152
153
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 147

def get_ty_data_header(response)
  if defined?(::HTTP) && defined?(::HTTP::Message) && response.class == ::HTTP::Message
    response.header[TY_DATA_HEADER].first.to_s rescue ""
  else
    response[TY_DATA_HEADER].to_s rescue ""
  end
end

.inject_request_headers(state, request) ⇒ Object

Inject the X-Process header into the outgoing request.



129
130
131
132
133
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 129

def inject_request_headers(state, request)
  cross_app_id  = TingYun::Agent.config[:tingyunIdSecret]

  request[TY_ID_HEADER] = "#{cross_app_id};c=1;x=#{state.request_guid}"
end

.metrics_for(request) ⇒ Object



109
110
111
112
113
114
115
116
117
118
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 109

def metrics_for(request)
  metrics = [ "External/NULL/ALL" ]
  if TingYun::Agent::Transaction.recording_web_transaction?
    metrics << "External/NULL/AllWeb"
  else
    metrics << "External/NULL/AllBackground"
  end
  metrics << "External/#{request.uri.to_s.gsub(/\/\z/,'').gsub('/','%2F')}/#{request.from}"
  return metrics
end

.metrics_for_cross_app(request, response) ⇒ Object



102
103
104
105
106
107
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 102

def metrics_for_cross_app(request, response)
  my_data =  TingYun::Support::Serialize::JSONWrapper.load get_ty_data_header(response).gsub("'",'"')
  metrics = ["ExternalTransaction/NULL/#{my_data["id"]}",
             "ExternalTransaction/http/#{my_data["id"]}"]
  metrics << "ExternalTransaction/#{request.uri.to_s.gsub(/\/\z/,'').gsub('/','%2F')}/#{my_data["id"]}%2F#{my_data["action"].to_s.gsub(/\/\z/,'')}"
end

.response_is_cross_app?(response) ⇒ Boolean

Returns true if Cross Application Tracing is enabled, and the given response has the appropriate headers.

Returns:

  • (Boolean)


137
138
139
140
141
142
143
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 137

def response_is_cross_app?( response )
  return false unless response
  return false unless cross_app_enabled?
  return false if get_ty_data_header(response).empty?

  return true
end

.start_trace(state, t0, request) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 45

def start_trace(state, t0, request)
  inject_request_headers(state, request) if cross_app_enabled?
  stack = state.traced_method_stack
  node = stack.push_frame(state, :http_request, t0)

  return node
end

.tl_trace_http_request(request) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ting_yun/agent/cross_app/cross_app_tracing.rb', line 29

def tl_trace_http_request(request)
  state = TingYun::Agent::TransactionState.tl_get
  return yield unless state.execution_traced?
  return yield unless state.current_transaction #如果还没有创建Transaction,就发生跨应用,就直接先跳过跟踪。

  t0 = Time.now.to_f
  begin
    node = start_trace(state, t0, request)
    response = yield
    capture_exception(response, request)
  ensure
    finish_trace(state, t0, node, request, response)
  end
  return response
end