Class: Datadog::Core::Crashtracking::Component
- Inherits:
-
Object
- Object
- Datadog::Core::Crashtracking::Component
- Defined in:
- lib/datadog/core/crashtracking/component.rb,
ext/libdatadog_api/crashtracker.c
Overview
Used to report Ruby VM crashes.
NOTE: The crashtracker native state is a singleton; so even if you create multiple instances of Crashtracking::Component and start them, it only works as “last writer wins”. Same for stop – there’s only one state, so calling stop on it will stop the crash tracker, regardless of which instance started it.
Methods prefixed with native are implemented in crashtracker.c
Class Method Summary collapse
- ._native_report_ruby_exception ⇒ Object
- ._native_start_or_update_on_fork ⇒ Object
- ._native_stop ⇒ Object
- .build(settings, agent_settings, logger:) ⇒ Object
-
.latest_tags(settings) ⇒ Object
Gets the latest tags from the current configuration.
-
.report_unhandled_exception(exception) ⇒ Object
Reports unhandled exceptions to the crash tracker if available and appropriate.
Instance Method Summary collapse
-
#initialize(tags:, agent_base_url:, ld_library_path:, path_to_crashtracking_receiver_binary:, logger:) ⇒ Component
constructor
A new instance of Component.
- #report_unhandled_exception(exception, settings: Datadog.configuration) ⇒ Object
- #start ⇒ Object
- #stop ⇒ Object
- #update_on_fork(settings: Datadog.configuration) ⇒ Object
Constructor Details
#initialize(tags:, agent_base_url:, ld_library_path:, path_to_crashtracking_receiver_binary:, logger:) ⇒ Component
Returns a new instance of Component.
70 71 72 73 74 75 76 |
# File 'lib/datadog/core/crashtracking/component.rb', line 70 def initialize(tags:, agent_base_url:, ld_library_path:, path_to_crashtracking_receiver_binary:, logger:) = @agent_base_url = agent_base_url @ld_library_path = ld_library_path @path_to_crashtracking_receiver_binary = path_to_crashtracking_receiver_binary @logger = logger end |
Class Method Details
._native_report_ruby_exception ⇒ Object
10 11 12 |
# File 'ext/libdatadog_api/crashtracker_report_exception.c', line 10 static VALUE _native_report_ruby_exception(VALUE _self, VALUE agent_base_url, VALUE , VALUE frames_data, VALUE , VALUE library_version); |
._native_start_or_update_on_fork ⇒ Object
7 |
# File 'ext/libdatadog_api/crashtracker.c', line 7 static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self); |
._native_stop ⇒ Object
8 |
# File 'ext/libdatadog_api/crashtracker.c', line 8 static VALUE _native_stop(DDTRACE_UNUSED VALUE _self); |
.build(settings, agent_settings, logger:) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/datadog/core/crashtracking/component.rb', line 19 def self.build(settings, agent_settings, logger:) = (settings) agent_base_url = agent_settings.url ld_library_path = ::Libdatadog.ld_library_path logger.warn('Missing ld_library_path; cannot enable crash tracking') unless ld_library_path path_to_crashtracking_receiver_binary = ::Libdatadog.path_to_crashtracking_receiver_binary unless path_to_crashtracking_receiver_binary logger.warn('Missing path_to_crashtracking_receiver_binary; cannot enable crash tracking') end return unless agent_base_url return unless ld_library_path return unless path_to_crashtracking_receiver_binary new( tags: , agent_base_url: agent_base_url, ld_library_path: ld_library_path, path_to_crashtracking_receiver_binary: path_to_crashtracking_receiver_binary, logger: logger ).tap(&:start) end |
.latest_tags(settings) ⇒ Object
Gets the latest tags from the current configuration.
We always fetch fresh tags because: After forking, we need the latest tags, not the parent’s tags, such as the pid or runtime-id
66 67 68 |
# File 'lib/datadog/core/crashtracking/component.rb', line 66 def self.(settings) TagBuilder.call(settings) end |
.report_unhandled_exception(exception) ⇒ Object
Reports unhandled exceptions to the crash tracker if available and appropriate. This is called from the at_exit hook to report unhandled exceptions.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/datadog/core/crashtracking/component.rb', line 46 def self.report_unhandled_exception(exception) return unless exception && !exception.is_a?(SystemExit) && !exception.is_a?(NoMemoryError) begin crashtracker = Datadog.send(:components, allow_initialization: false)&.crashtracker return unless crashtracker crashtracker.report_unhandled_exception(exception) rescue => e # Unhandled exception report triggering means that the application is already in a bad state # We don't want to swallow non-StandardError exceptions here; we would rather just let the # application crash Datadog.logger.debug("Crashtracker failed to report unhandled exception: #{e.message}") end end |
Instance Method Details
#report_unhandled_exception(exception, settings: Datadog.configuration) ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 129 130 131 132 133 134 135 |
# File 'lib/datadog/core/crashtracking/component.rb', line 86 def report_unhandled_exception(exception, settings: Datadog.configuration) # Maximum number of stack frames to include in exception crash reports # This is the same number used for signal-based crashtracking's runtime stack max_exception_stack_frames = 512 = self.class.(settings) # extract all frame data upfront; c expects exactly 3 elements, proper types, no nils # limit to max_exception_stack_frames frames all_backtrace_locations = exception.backtrace_locations || [] was_truncated = all_backtrace_locations.length > max_exception_stack_frames backtrace_slice = all_backtrace_locations[0...max_exception_stack_frames] || [] # @type var frames_data: Array[[String, String, Integer]] frames_data = backtrace_slice.map do |loc| file = loc.path file = '<unknown>' if file.nil? || file.empty? || !file.is_a?(String) function = loc.label function = '<unknown>' if function.nil? || function.empty? || !function.is_a?(String) line = loc.lineno line = 0 if line.nil? || line < 0 || !line.is_a?(Integer) [file, function, line] end # Add truncation indicator frame if we had to cut off frames if was_truncated truncated_count = all_backtrace_locations.length - max_exception_stack_frames frames_data << ['<truncated>', "<truncated #{truncated_count} more frames>", 0] end = exception. = if && !.empty? "Process was terminated due to an unhandled exception of type '#{exception.class}'. Message: \"#{exception_message}\"" else "Process was terminated due to an unhandled exception of type '#{exception.class}'." end success = self.class._native_report_ruby_exception( agent_base_url, , frames_data, .to_a, Datadog::VERSION::STRING ) logger.debug('Crashtracker failed to report unhandled exception to crash tracker') unless success end |
#start ⇒ Object
78 79 80 |
# File 'lib/datadog/core/crashtracking/component.rb', line 78 def start start_or_update_on_fork(action: :start, tags: ) end |
#stop ⇒ Object
137 138 139 140 141 142 |
# File 'lib/datadog/core/crashtracking/component.rb', line 137 def stop self.class._native_stop logger.debug('Crash tracking stopped successfully') rescue => e logger.error("Failed to stop crash tracking: #{e.message}") end |
#update_on_fork(settings: Datadog.configuration) ⇒ Object
82 83 84 |
# File 'lib/datadog/core/crashtracking/component.rb', line 82 def update_on_fork(settings: Datadog.configuration) start_or_update_on_fork(action: :update_on_fork, tags: self.class.(settings)) end |