Class: TingYun::Agent::Collector::TransactionSampler

Inherits:
Object
  • Object
show all
Defined in:
lib/ting_yun/agent/collector/transaction_sampler.rb,
lib/ting_yun/agent/collector/transaction_sampler/slowest_sample_buffer.rb,
lib/ting_yun/agent/collector/transaction_sampler/transaction_sample_buffer_base.rb

Defined Under Namespace

Classes: SlowestSampleBuffer, TransactionSampleBufferBase

Constant Summary collapse

MAX_DATA_LENGTH =
16384

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTransactionSampler

Returns a new instance of TransactionSampler.



18
19
20
21
22
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 18

def initialize
  @lock = Mutex.new
  @sample_buffers = []
  @sample_buffers << TingYun::Agent::Collector::TransactionSampler::SlowestSampleBuffer.new
end

Instance Attribute Details

#last_sampleObject

Returns the value of attribute last_sample.



15
16
17
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 15

def last_sample
  @last_sample
end

Class Method Details

.truncate_message(message) ⇒ Object

Truncates the message to ‘MAX_DATA_LENGTH` if needed, and appends an ellipsis because it makes the trucation clearer in the UI



147
148
149
150
151
152
153
154
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 147

def self.truncate_message(message)
  if message.length > (MAX_DATA_LENGTH - 4)
    message.slice!(MAX_DATA_LENGTH - 4..message.length)
    message << '...'
  else
    message
  end
end

Instance Method Details

#action_tracer_segment(builder, message, duration, key) ⇒ Object

This method is used to record metadata into the currently active node like a sql query, memcache key, or Net::HTTP uri

duration is milliseconds, float value. duration=> sec



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 125

def action_tracer_segment(builder, message, duration, key)
  return unless builder
  node = builder.current_node
  if node
    if key == :sql
      statement = node[:sql]
      if statement && !statement.sql.empty?
        statement.sql = self.class.truncate_message(statement.sql + "\n#{message.sql}") if statement.sql.length <= MAX_DATA_LENGTH
      else
        # message is expected to have been pre-truncated by notice_sql
        node[:sql] =  message
      end
    else
      node[key] = self.class.truncate_message(message)
    end
    append_backtrace(node, duration)
  end
end

#add_node_info(params) ⇒ Object



215
216
217
218
219
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 215

def add_node_info(params)
  builder = tl_builder
  return unless builder
  params.each { |k,v| builder.current_node.instance_variable_set(('@'<<k.to_s).to_sym, v)  }
end

#append_backtrace(node, duration) ⇒ Object

Appends a backtrace to a node if that node took longer than the specified duration



158
159
160
161
162
163
164
165
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 158

def append_backtrace(node, duration)
  if duration*1000 >= Agent.config[:'nbs.action_tracer.stack_trace_threshold']
    trace =  caller.reject! { |t| t.include?('tingyun_rpm') }
    trace = trace.first(20)
    node[:stacktrace] = trace
  end

end

#enabled?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 38

def enabled?
  TingYun::Agent.config[:'nbs.action_tracer.enabled']
end

#harvest!Object



167
168
169
170
171
172
173
174
175
176
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 167

def harvest!
  return [] unless enabled?

  samples = @lock.synchronize do
    @last_sample = nil
    harvest_from_sample_buffers
  end

  prepare_samples(samples)
end

#harvest_from_sample_buffersObject



178
179
180
181
182
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 178

def harvest_from_sample_buffers
  result = []
  @sample_buffers.each { |buffer| result.concat(buffer.harvest_samples) }
  result.uniq
end

#merge!(previous) ⇒ Object



199
200
201
202
203
204
205
206
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 199

def merge!(previous)

  @lock.synchronize do
    @sample_buffers.each do |buffer|
      buffer.store_previous(previous)
    end
  end
end

#notice_nosql(key, duration) ⇒ Object

duration=> sec



104
105
106
107
108
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 104

def notice_nosql(key, duration) #THREAD_LOCAL_ACCESS
  builder = tl_builder
  return unless builder
  action_tracer_segment(builder, key, duration, :key)
end

#notice_nosql_statement(statement, duration) ⇒ Object

duration=> sec



111
112
113
114
115
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 111

def notice_nosql_statement(statement, duration) #THREAD_LOCAL_ACCESS
  builder = tl_builder
  return unless builder
  action_tracer_segment(builder, statement, duration, :statement)
end

#notice_pop_frame(state, frame, time = Time.now) ⇒ Object

Informs the transaction sample builder about the end of a traced frame



32
33
34
35
36
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 32

def notice_pop_frame(state, frame, time = Time.now)
  builder = state.transaction_sample_builder
  return unless builder
  builder.trace_exit(frame, time.to_f)
end

#notice_push_frame(state, time = Time.now) ⇒ Object



25
26
27
28
29
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 25

def notice_push_frame(state, time=Time.now)
  builder = state.transaction_sample_builder
  return unless builder
  builder.trace_entry(time.to_f)
end

#notice_sql(sql, config, duration, state = nil, explainer = nil) ⇒ Object

Attaches an SQL query on the current transaction trace node. duration=> sec

Parameters:

  • sql (String)

    the SQL query being recorded

  • config (Object)

    the driver configuration for the connection

  • duration (Float)

    number of seconds the query took to execute

  • explainer (Proc) (defaults to: nil)

    for internal use only - 3rd-party clients must not pass this parameter.



92
93
94
95
96
97
98
99
100
101
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 92

def notice_sql(sql, config, duration, state=nil, explainer=nil)
  # some statements (particularly INSERTS with large BLOBS
  # may be very large; we should trim them to a maximum usable length
  state ||= TingYun::Agent::TransactionState.tl_get
  builder = state.transaction_sample_builder
  if state.sql_recorded?
    statement = TingYun::Agent::Database::Statement.new(sql, config, explainer)
    action_tracer_segment(builder, statement, duration, :sql)
  end
end

#on_finishing_transaction(state, txn, time = Time.now.to_f) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 55

def on_finishing_transaction(state, txn, time=Time.now.to_f)
  last_builder = state.transaction_sample_builder
  return unless last_builder && enabled?

  last_builder.finish_trace(time)

  state.transaction_sample_builder = nil


  final_trace = last_builder.trace
  final_trace.metric_name = txn.best_name
  final_trace.uri = txn.request_path
  final_trace.attributes = txn.attributes


  @lock.synchronize do
    @last_sample = final_trace

    store_sample(@last_sample)
    @last_sample
  end
end

#on_start_transaction(state, time) ⇒ Object



42
43
44
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 42

def on_start_transaction(state, time)
  start_builder(state, time)
end

#prepare_samples(samples) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 184

def prepare_samples(samples)
  samples.select do |sample|
    begin
      sample.prepare_to_send!
    rescue => e

      TingYun::Agent.logger.error('Failed to prepare transaction trace. Error: ', e)

      false
    else
      true
    end
  end
end

#reset!Object



208
209
210
211
212
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 208

def reset!
  @lock.synchronize do
    @sample_buffers.each { |sample| sample.reset! }
  end
end

#start_builder(state, time = nil) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 46

def start_builder(state, time=nil)
  if enabled?
    state.transaction_sample_builder ||= TingYun::Agent::TransactionSampleBuilder.new(time)
  else
    state.transaction_sample_builder = nil
  end
end

#store_sample(sample) ⇒ Object



78
79
80
81
82
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 78

def store_sample(sample)
  @sample_buffers.each do |sample_buffer|
    sample_buffer.store(sample)
  end
end

#tl_builderObject



221
222
223
# File 'lib/ting_yun/agent/collector/transaction_sampler.rb', line 221

def tl_builder
  TingYun::Agent::TransactionState.tl_get.transaction_sample_builder
end