Class: Datadog::ErrorTracking::Component Private

Inherits:
Object
  • Object
show all
Defined in:
lib/datadog/error_tracking/component.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Component for Error Tracking.

Only one instance of the Component should ever be active.

The component instance records every handled exceptions from the configured scopes (user, third_party packages, specified files or everything).

API:

  • private

Constant Summary collapse

LOCK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

API:

  • private

Mutex.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tracer:, handled_errors:, handled_errors_include:) ⇒ Component

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Component.

API:

  • private



48
49
50
51
52
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
# File 'lib/datadog/error_tracking/component.rb', line 48

def initialize(tracer:, handled_errors:, handled_errors_include:)
  @tracer = tracer

  # Hash containing the paths to the instrumented files
  @instrumented_files = Set.new unless handled_errors_include.empty?
  # Array containing file paths, file names and gems names to instrument.
  # This is coming from the DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE env variable
  @handled_errors_include = handled_errors_include

  # Filter function is used to filter out the exception
  # we do not want to report. For instance exception from gems.
  @filter_function = Filters.generate_filter(handled_errors, @instrumented_files)

  # :rescue event was added in Ruby 3.3
  #
  # Before Ruby3.3 the TracePoint listen for :raise events.
  # If an error is not handled, we will delete the according
  # span event in the collector.
  event = (RUBY_VERSION >= '3.3') ? :rescue : :raise

  # This TracePoint is in charge of capturing the handled exceptions
  # and of adding the corresponding span events to the collector
  @handled_exc_tracker = create_exc_tracker_trace_point(event)

  if @instrumented_files
    # The only thing we know about the handled errors is the path of the file
    # in which the error was rescued. Therefore, we need to retrieve the path
    # of the files the user want to instrument. This TracePoint is used for that
    # purpose
    @include_path_getter = create_script_compiled_trace_point
  end
end

Class Method Details

.build(settings, tracer, logger) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/datadog/error_tracking/component.rb', line 19

def build(settings, tracer, logger)
  return if !settings.respond_to?(:error_tracking) || (settings.error_tracking.handled_errors.nil? &&
    settings.error_tracking.handled_errors_include.empty?)

  return unless environment_supported?(logger)

  new(
    tracer: tracer,
    handled_errors: settings.error_tracking.handled_errors,
    handled_errors_include: settings.error_tracking.handled_errors_include,
  ).tap(&:start)
end

.environment_supported?(logger) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

API:

  • private



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/datadog/error_tracking/component.rb', line 32

def environment_supported?(logger)
  if RUBY_ENGINE != 'ruby'
    logger.warn("error tracking: cannot enable error tracking: MRI is required, but running on #{RUBY_ENGINE}")
    false
  elsif RUBY_VERSION < '2.7'
    logger.warn(
      "error tracking: cannot enable error tracking: Ruby 2.7+ is required, but running
      on #{RUBY_VERSION}"
    )
    false
  else
    true
  end
end

Instance Method Details

#create_exc_tracker_trace_point(event) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/datadog/error_tracking/component.rb', line 81

def create_exc_tracker_trace_point(event)
  TracePoint.new(event) do |tp|
    active_span = @tracer.active_span
    if active_span
      raised_exception = tp.raised_exception
      # Note that in 3.2, this will give the path of where the error was raised
      # which may cause the handled_error_include env variable to malfunction.
      rescue_file_path = tp.path
      if @filter_function.call(rescue_file_path)
        span_event = generate_span_event(raised_exception)
        LOCK.synchronize do
          collector = active_span.get_collector_or_initialize { Collector.new }
          collector.add_span_event(active_span, span_event, raised_exception)
        end
      end
    end
  end
end

#create_script_compiled_trace_pointObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/datadog/error_tracking/component.rb', line 100

def create_script_compiled_trace_point
  TracePoint.new(:script_compiled) do |tp|
    next if tp.eval_script

    path = tp.instruction_sequence.path
    next if path.nil?

    @handled_errors_include.each do |file_to_instr|
      # The user can provide either
      # - absolute_path starting with '/'. In that case the path of the file
      #   should begin with file_to_instr
      # - a relative_path starting with './'. In that case, we extend the path
      #   and it is the same as above
      # - otherwise we just check if the name provided is in the path and is
      #   either the name of a folder or of a ruby file.
      regex =
        if file_to_instr.start_with?('/')
          %r{\A#{Regexp.escape(file_to_instr)}(?:/|\.rb\z|\z)}
        elsif file_to_instr.start_with?('./')
          abs_path = File.expand_path(file_to_instr)
          %r{\A#{Regexp.escape(abs_path)}(?:/|\.rb\z|\z)}
        else
          %r{/#{Regexp.escape(file_to_instr)}(?:/|\.rb\z|\z)}
        end

      add_instrumented_file(path) if path.match?(regex)
    end
  end
end

#shutdown!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Shuts down error tracker.

Disables the TracePoints.

API:

  • private



141
142
143
144
# File 'lib/datadog/error_tracking/component.rb', line 141

def shutdown!
  @handled_exc_tracker.disable
  @include_path_getter&.disable
end

#startObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Starts the TracePoints.

Enables the script_compiled TracePoint if handled_errors_include is not empty.

API:

  • private



133
134
135
136
# File 'lib/datadog/error_tracking/component.rb', line 133

def start
  @handled_exc_tracker.enable
  @include_path_getter&.enable
end