Class: XRay::Recorder

Inherits:
Object
  • Object
show all
Defined in:
lib/aws-xray-sdk/recorder.rb

Overview

A global AWS X-Ray recorder that will begin/end segments/subsegments and send them to the X-Ray daemon. It is also responsible for managing context.

Direct Known Subclasses

LambdaRecorder

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_config: nil) ⇒ Recorder

Returns a new instance of Recorder.



17
18
19
20
21
# File 'lib/aws-xray-sdk/recorder.rb', line 17

def initialize(user_config: nil)
  @config = Configuration.new
  @config.configure(user_config) unless user_config.nil?
  @origin = nil
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



15
16
17
# File 'lib/aws-xray-sdk/recorder.rb', line 15

def config
  @config
end

#originObject (readonly)

Returns the value of attribute origin.



15
16
17
# File 'lib/aws-xray-sdk/recorder.rb', line 15

def origin
  @origin
end

Instance Method Details

#annotationsObject

A proxy method to get the annotations from the current active entity.



157
158
159
160
161
162
163
164
# File 'lib/aws-xray-sdk/recorder.rb', line 157

def annotations
  entity = current_entity
  if entity
    entity.annotations
  else
    FacadeAnnotations
  end
end

#begin_segment(name, trace_id: nil, parent_id: nil, sampled: nil) ⇒ Segment

Begin a segment for the current context. The recorder only keeps one segment at a time. Create a second one without closing existing one will overwrite the existing one.

Returns:

  • (Segment)

    thew newly created segment.

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/aws-xray-sdk/recorder.rb', line 27

def begin_segment(name, trace_id: nil, parent_id: nil, sampled: nil)
  seg_name = name || config.name
  raise SegmentNameMissingError if seg_name.to_s.empty?

  # sampling decision comes from outside has higher precedence.
  sample = sampled.nil? ? config.sample? : sampled
  if sample
    segment = Segment.new name: seg_name, trace_id: trace_id, parent_id: parent_id
    populate_runtime_context(segment, sample)
  else
    segment = DummySegment.new name: seg_name, trace_id: trace_id, parent_id: parent_id
  end
  context.store_entity entity: segment
  segment
end

#begin_subsegment(name, namespace: nil, segment: nil) ⇒ Subsegment

Begin a new subsegment and add it to be the child of the current active subsegment or segment. Also tie the new created subsegment to the current context. Its sampling decision will follow its parent.

Returns:

  • (Subsegment)

    the newly created subsegment. It could be ‘nil` if no active entity can be found and `context_missing` is set to `LOG_ERROR`.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/aws-xray-sdk/recorder.rb', line 64

def begin_subsegment(name, namespace: nil, segment: nil)
  entity = segment || current_entity
  return unless entity
  if entity.sampled
    subsegment = Subsegment.new name: name, segment: entity.segment, namespace: namespace
  else
    subsegment = DummySubsegment.new name: name, segment: entity.segment
  end
  # attach the new created subsegment under the current active entity
  entity.add_subsegment subsegment: subsegment
  # associate the new subsegment to the current context
  context.store_entity entity: subsegment
  subsegment
end

#capture(name, namespace: nil, segment: nil) ⇒ Object

Record the passed block as a subsegment. If ‘context_missing` is set to `LOG_ERROR` and no active entity can be found, the passed block will be executed as normal but it will not be recorded.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/aws-xray-sdk/recorder.rb', line 112

def capture(name, namespace: nil, segment: nil)
  subsegment = begin_subsegment name, namespace: namespace, segment: segment
  # prevent passed block from failing in case of context missing with log error
  if subsegment.nil?
    segment = DummySegment.new name: name
    subsegment = DummySubsegment.new name: name, segment: segment
  end

  begin
    yield subsegment
  rescue Exception => e
    subsegment.add_exception exception: e
    raise e
  ensure
    end_subsegment
  end
end

#clear_contextObject



143
144
145
# File 'lib/aws-xray-sdk/recorder.rb', line 143

def clear_context
  context.clear!
end

#configure(user_config) ⇒ Object

A proxy method to XRay::Configuration.configure



178
179
180
# File 'lib/aws-xray-sdk/recorder.rb', line 178

def configure(user_config)
  config.configure(user_config)
end

#contextObject



182
183
184
# File 'lib/aws-xray-sdk/recorder.rb', line 182

def context
  config.context
end

#current_entityObject

Returns current segment or subsegment that associated to the current context. This is a proxy method to Context class current_entity.



132
133
134
# File 'lib/aws-xray-sdk/recorder.rb', line 132

def current_entity
  context.current_entity
end

#current_segmentSegment

Returns the active segment tied to the current context. If the current context is under a subsegment, it returns its parent segment.

Returns:

  • (Segment)

    the active segment tied to the current context. If the current context is under a subsegment, it returns its parent segment.



45
46
47
48
# File 'lib/aws-xray-sdk/recorder.rb', line 45

def current_segment
  entity = current_entity
  entity.segment if entity
end

#current_subsegmentSubsegment

The active subsegment tied to the current context. Returns nil if the current context has no associated subsegment.

Returns:

  • (Subsegment)

    the active subsegment tied to the current context. Returns nil if the current context has no associated subsegment.



81
82
83
84
# File 'lib/aws-xray-sdk/recorder.rb', line 81

def current_subsegment
  entity = context.current_entity
  entity.is_a?(Subsegment) ? entity : nil
end

#emitterObject



190
191
192
# File 'lib/aws-xray-sdk/recorder.rb', line 190

def emitter
  config.emitter
end

#end_segment(end_time: nil) ⇒ Object

End the current segment and send it to X-Ray daemon if it is ready.



51
52
53
54
55
56
57
# File 'lib/aws-xray-sdk/recorder.rb', line 51

def end_segment(end_time: nil)
  segment = current_segment
  return unless segment
  segment.close end_time: end_time
  context.clear!
  emitter.send_entity entity: segment if segment.ready_to_send?
end

#end_subsegment(end_time: nil) ⇒ Object

End the current active subsegment. It also send the entire segment if this subsegment is the last one open or stream out subsegments of its parent segment if the stream threshold is breached.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/aws-xray-sdk/recorder.rb', line 89

def end_subsegment(end_time: nil)
  entity = current_entity
  return unless entity.is_a?(Subsegment)
  entity.close end_time: end_time
  # update current context
  if entity.parent.closed?
    context.clear!
  else
    context.store_entity entity: entity.parent
  end
  # check if the entire segment can be send.
  # If not, stream subsegments when threshold is reached.
  segment = entity.segment
  if segment.ready_to_send?
    emitter.send_entity entity: segment
  elsif streamer.eligible? segment: segment
    streamer.stream_subsegments root: segment, emitter: emitter
  end
end

#inject_context(entity, target_ctx: nil) ⇒ Object



136
137
138
139
140
141
# File 'lib/aws-xray-sdk/recorder.rb', line 136

def inject_context(entity, target_ctx: nil)
  context.inject_context entity, target_ctx: target_ctx
  return unless block_given?
  yield
  context.clear!
end

#metadata(namespace: :default) ⇒ Object

A proxy method to get the metadata under provided namespace from the current active entity.



168
169
170
171
172
173
174
175
# File 'lib/aws-xray-sdk/recorder.rb', line 168

def (namespace: :default)
  entity = current_entity
  if entity
    entity.(namespace: namespace)
  else
    FacadeMetadata
  end
end

#populate_runtime_context(segment, sample) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/aws-xray-sdk/recorder.rb', line 208

def populate_runtime_context(segment, sample)
  @aws ||= begin
    aws = {}
    config.plugins.each do |p|
      meta = p.aws
      if meta.is_a?(Hash) && !meta.empty?
        aws.merge! meta
        @origin = p::ORIGIN
      end
    end
    xray_meta = { xray:
      {
        sdk_version: XRay::VERSION,
        sdk: 'X-Ray for Ruby'
      }
    }
    aws.merge! xray_meta
  end

  @service ||= {
    runtime: RUBY_ENGINE,
    runtime_version: RUBY_VERSION
  }

  segment.aws = @aws
  segment.service = @service
  segment.origin = @origin
  segment.sampling_rule_name = sample if sample.is_a?(String)
end

#sampled?Boolean

Returns:

  • (Boolean)


147
148
149
150
151
152
153
154
# File 'lib/aws-xray-sdk/recorder.rb', line 147

def sampled?
  entity = current_entity
  if block_given?
    yield if entity && entity.sampled
  else
    entity && entity.sampled
  end
end

#samplerObject



186
187
188
# File 'lib/aws-xray-sdk/recorder.rb', line 186

def sampler
  config.sampler
end

#sampling_enabled?Boolean

Returns:

  • (Boolean)


202
203
204
# File 'lib/aws-xray-sdk/recorder.rb', line 202

def sampling_enabled?
  config.sampling
end

#segment_namingObject



198
199
200
# File 'lib/aws-xray-sdk/recorder.rb', line 198

def segment_naming
  config.segment_naming
end

#streamerObject



194
195
196
# File 'lib/aws-xray-sdk/recorder.rb', line 194

def streamer
  config.streamer
end