Class: NewRelic::TransactionSample::Segment

Inherits:
Object
  • Object
show all
Defined in:
lib/new_relic/transaction_sample.rb

Direct Known Subclasses

CompositeSegment, SummarySegment

Constant Summary collapse

@@empty_array =
[]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(timestamp, metric_name, segment_id) ⇒ Segment

Returns a new instance of Segment.



33
34
35
36
37
# File 'lib/new_relic/transaction_sample.rb', line 33

def initialize(timestamp, metric_name, segment_id)
  @entry_timestamp = timestamp
  @metric_name = metric_name
  @segment_id = segment_id || object_id
end

Instance Attribute Details

#entry_timestampObject (readonly)

Returns the value of attribute entry_timestamp.



27
28
29
# File 'lib/new_relic/transaction_sample.rb', line 27

def 
  @entry_timestamp
end

#exit_timestampObject (readonly)

Returns the value of attribute exit_timestamp.



28
29
30
# File 'lib/new_relic/transaction_sample.rb', line 28

def exit_timestamp
  @exit_timestamp
end

#metric_nameObject (readonly)

Returns the value of attribute metric_name.



30
31
32
# File 'lib/new_relic/transaction_sample.rb', line 30

def metric_name
  @metric_name
end

#parent_segmentObject

Returns the value of attribute parent_segment.



29
30
31
# File 'lib/new_relic/transaction_sample.rb', line 29

def parent_segment
  @parent_segment
end

#segment_idObject (readonly)

Returns the value of attribute segment_id.



31
32
33
# File 'lib/new_relic/transaction_sample.rb', line 31

def segment_id
  @segment_id
end

Instance Method Details

#[](key) ⇒ Object



116
117
118
# File 'lib/new_relic/transaction_sample.rb', line 116

def [](key)
  params[key]
end

#[]=(key, value) ⇒ Object



110
111
112
113
114
# File 'lib/new_relic/transaction_sample.rb', line 110

def []=(key, value)
  # only create a parameters field if a parameter is set; this will save
  # bandwidth etc as most segments have no parameters
  params[key] = value
end

#add_called_segment(s) ⇒ Object



43
44
45
46
47
# File 'lib/new_relic/transaction_sample.rb', line 43

def add_called_segment(s)
  @called_segments ||= []
  @called_segments << s
  s.parent_segment = self
end

#called_segmentsObject



78
79
80
# File 'lib/new_relic/transaction_sample.rb', line 78

def called_segments
  @called_segments || @@empty_array
end

#called_segments=(segments) ⇒ Object



192
193
194
# File 'lib/new_relic/transaction_sample.rb', line 192

def called_segments=(segments)
  @called_segments = segments
end

#durationObject

return the total duration of this segment



93
94
95
# File 'lib/new_relic/transaction_sample.rb', line 93

def duration
  @exit_timestamp - @entry_timestamp
end

#each_segment(&block) ⇒ Object

call the provided block for this segment and each of the called segments



126
127
128
129
130
131
132
133
134
# File 'lib/new_relic/transaction_sample.rb', line 126

def each_segment(&block)
  block.call self
  
  if @called_segments
    @called_segments.each do |segment|
      segment.each_segment(&block)
    end
  end
end

#end_trace(timestamp) ⇒ Object



39
40
41
# File 'lib/new_relic/transaction_sample.rb', line 39

def end_trace(timestamp)
  @exit_timestamp = timestamp
end

#exclusive_durationObject

return the duration of this segment without including the time in the called segments



99
100
101
102
103
104
105
106
107
108
# File 'lib/new_relic/transaction_sample.rb', line 99

def exclusive_duration
  d = duration
  
  if @called_segments
    @called_segments.each do |segment|
      d -= segment.duration
    end
  end
  d
end

#explain_sqlObject

perform this in the runtime environment of a managed application, to explain the sql statement(s) executed within a segment of a transaction sample. returns an array of explanations (which is an array rows consisting of an array of strings for each column returned by the the explain query) Note this happens only for statements whose execution time exceeds a threshold (e.g. 500ms) and only within the slowest transaction in a report period, selected for shipment to RPM



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/new_relic/transaction_sample.rb', line 151

def explain_sql        
  sql = params[:sql]
  return nil unless sql && params[:connection_config]
  statements = sql.split(";\n")
  explanations = []
  statements.each do |statement|
    if statement.split($;, 2)[0].upcase == 'SELECT'
      explain_resultset = []
      begin
        connection = NewRelic::TransactionSample.get_connection(params[:connection_config])    
        if connection
          # The resultset type varies for different drivers.  Only thing you can count on is
          # that it implements each.  Also: can't use select_rows because the native postgres
          # driver doesn't know that method.
          explain_resultset = connection.execute("EXPLAIN #{statement}") if connection
          rows = []
          # Note: we can't use map.
          # Note: have to convert from native column element types to string so we can
          # serialize.  Esp. for postgresql.
          explain_resultset.each { | row | rows << row.map(&:to_s) }  # Can't use map.  Suck it up.
          explanations << rows
          # sleep for a very short period of time in order to yield to the main thread
          # this is because a remote database call will likely hang the VM
          sleep 0.05
        end
      rescue => e
        x = 1 # this is here so that code coverage knows we've entered this block
        # swallow failed attempts to run an explain.  One example of a failure is the
        # connection for the sql statement is to a different db than the default connection
        # specified in AR::Base
      end
    end
  end

  explanations
end

#find_segment(id) ⇒ Object



136
137
138
139
140
141
142
143
# File 'lib/new_relic/transaction_sample.rb', line 136

def find_segment(id)
  return self if @segment_id == id
  called_segments.each do |segment|
    found = segment.find_segment(id)
    return found if found
  end
  nil
end

#freezeObject



82
83
84
85
86
87
88
89
90
# File 'lib/new_relic/transaction_sample.rb', line 82

def freeze
  params.freeze
  if @called_segments
    @called_segments.each do |s|
      s.freeze
    end
  end
  super
end

#obfuscated_sqlObject



188
189
190
# File 'lib/new_relic/transaction_sample.rb', line 188

def obfuscated_sql
  TransactionSample.obfuscate_sql(params[:sql])
end

#paramsObject



120
121
122
# File 'lib/new_relic/transaction_sample.rb', line 120

def params
  @params ||= {}
end

#path_stringObject



53
54
55
# File 'lib/new_relic/transaction_sample.rb', line 53

def path_string
  "#{metric_name}[#{called_segments.collect {|segment| segment.path_string }.join('')}]"
end

#to_debug_str(depth) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/new_relic/transaction_sample.rb', line 57

def to_debug_str(depth)
  tab = "" 
  depth.times {tab << "  "}
  
  s = tab.clone
  s << ">> #{metric_name}: #{@entry_timestamp.to_ms}\n"
  unless params.empty?
    s << "#{tab}#{tab}{\n"
    params.each do |k,v|
      s << "#{tab}#{tab}#{k}: #{v}\n"
    end
    s << "#{tab}#{tab}}\n"
  end
  called_segments.each do |cs|
    s << cs.to_debug_str(depth + 1)
  end
  s << tab
  s << "<< #{metric_name}: #{@exit_timestamp ? @exit_timestamp.to_ms : 'n/a'}\n"
  s
end

#to_sObject



49
50
51
# File 'lib/new_relic/transaction_sample.rb', line 49

def to_s
  to_debug_str(0)
end