Class: OpenTelemetry::Instrumentation::RSpec::Formatter

Inherits:
Object
  • Object
show all
Defined in:
lib/opentelemetry/instrumentation/rspec/formatter.rb

Overview

An RSpec Formatter that outputs Otel spans

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output = StringIO.new, tracer_provider = OpenTelemetry.tracer_provider) ⇒ Formatter

Returns a new instance of Formatter.



25
26
27
28
29
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 25

def initialize(output = StringIO.new, tracer_provider = OpenTelemetry.tracer_provider)
  @spans_and_tokens = []
  @output = output
  @tracer_provider = tracer_provider
end

Instance Attribute Details

#outputObject (readonly)

Returns the value of attribute output.



15
16
17
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 15

def output
  @output
end

Class Method Details

.current_timestampObject



21
22
23
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 21

def self.current_timestamp
  @clock.call
end

Instance Method Details

#add_exception_and_failures(span, exception) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 79

def add_exception_and_failures(span, exception)
  return if exception.nil?

  exception_message = strip_console_codes(exception.message)
  span.status = OpenTelemetry::Trace::Status.error(exception_message)

  span.set_attribute('rspec.example.failure_message', exception_message) if exception.is_a? ::RSpec::Expectations::ExpectationNotMetError

  if exception.is_a? ::RSpec::Core::MultipleExceptionError
    exception.all_exceptions.each do |error|
      record_stripped_exception(span, error)
    end
    span.set_attribute('rspec.example.failure_message', multiple_failure_message(exception)) if exception.failures.any?
  else
    span.record_exception(exception, attributes: { 'exception.message' => exception_message })
  end
end

#current_timestampObject



35
36
37
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 35

def current_timestamp
  self.class.current_timestamp
end

#example_finished(notification) ⇒ Object



69
70
71
72
73
74
75
76
77
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 69

def example_finished(notification)
  pop_and_finalize_span do |span|
    result = notification.example.execution_result

    span.set_attribute('rspec.example.result', result.status.to_s)

    add_exception_and_failures(span, result.exception)
  end
end

#example_group_finished(notification) ⇒ Object



54
55
56
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 54

def example_group_finished(notification)
  pop_and_finalize_span
end

#example_group_started(notification) ⇒ Object



48
49
50
51
52
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 48

def example_group_started(notification)
  description = notification.group.description
  span = tracer.start_span(description, start_timestamp: current_timestamp)
  track_span(span)
end

#example_started(notification) ⇒ Object



58
59
60
61
62
63
64
65
66
67
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 58

def example_started(notification)
  example = notification.example
  attributes = {
    'rspec.example.location' => example.location.to_s,
    'rspec.example.full_description' => example.full_description.to_s,
    'rspec.example.described_class' => example.[:described_class].to_s
  }
  span = tracer.start_span(example.description, attributes: attributes, start_timestamp: current_timestamp)
  track_span(span)
end

#multiple_failure_message(exception) ⇒ Object



123
124
125
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 123

def multiple_failure_message(exception)
  exception.failures.map(&:message).map(&method(:strip_console_codes)).join("\n\n")
end

#pop_and_finalize_span {|span| ... } ⇒ Object

Yields:

  • (span)


104
105
106
107
108
109
110
111
112
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 104

def pop_and_finalize_span
  span, token = *@spans_and_tokens.shift
  return unless span.recording?

  yield span if block_given?

  span.finish(end_timestamp: current_timestamp)
  OpenTelemetry::Context.detach(token)
end

#record_stripped_exception(span, error) ⇒ Object



114
115
116
117
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 114

def record_stripped_exception(span, error)
  error_message = strip_console_codes(error.message)
  span.record_exception(error, attributes: { 'exception.message' => error_message })
end

#start(notification) ⇒ Object



39
40
41
42
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 39

def start(notification)
  span = tracer.start_span('RSpec suite', start_timestamp: current_timestamp)
  track_span(span)
end

#stop(notification) ⇒ Object



44
45
46
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 44

def stop(notification)
  pop_and_finalize_span
end

#strip_console_codes(string) ⇒ Object



119
120
121
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 119

def strip_console_codes(string)
  string.gsub(/\e\[([;\d]+)?m/, '')
end

#tracerObject



31
32
33
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 31

def tracer
  @tracer ||= @tracer_provider.tracer('OpenTelemetry::Instrumentation::RSpec', OpenTelemetry::Instrumentation::RSpec::VERSION)
end

#track_span(span) ⇒ Object



97
98
99
100
101
102
# File 'lib/opentelemetry/instrumentation/rspec/formatter.rb', line 97

def track_span(span)
  token = OpenTelemetry::Context.attach(
    OpenTelemetry::Trace.context_with_span(span)
  )
  @spans_and_tokens.unshift([span, token])
end