Skip to content

Commit 27067c0

Browse files
committed
Update to support constant_exception_message and ProfilingError
This gets us closer to allowing these errors to be sent to telemetry.
1 parent 8e2bf94 commit 27067c0

File tree

7 files changed

+61
-14
lines changed

7 files changed

+61
-14
lines changed

lib/datadog/core/telemetry/logging.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ def report(exception, level: :error, description: nil)
4949
# Anonymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
5050
message = +"#{exception.class.name || exception.class.inspect}" # standard:disable Style/RedundantInterpolation
5151

52-
message << ": #{description}" if description
52+
exception_message = constant_exception_message(exception)
53+
54+
if description || exception_message
55+
message << ':'
56+
message << " #{description}" if description
57+
message << " (#{exception_message})" if exception_message
58+
end
5359

5460
event = Event::Log.new(
5561
message: message,
@@ -62,9 +68,9 @@ def report(exception, level: :error, description: nil)
6268

6369
private
6470

65-
def safe_exception_message(exception)
66-
# Only include exception messages from ProfilingError, as those are guaranteed to be created by us
67-
# with constant, PII-safe messages
71+
def constant_exception_message(exception)
72+
# Only include exception messages from ProfilingError, as those are guaranteed to contain
73+
# constant strings created by Datadog code (not dynamic/PII content)
6874
if defined?(Datadog::Profiling::ProfilingError) && exception.is_a?(Datadog::Profiling::ProfilingError)
6975
exception.message
7076
end

sig/datadog/profiling.rbs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module Datadog
22
module Profiling
3+
class ProfilingError < StandardError
4+
end
5+
36
def self.supported?: () -> bool
47
def self.unsupported_reason: () -> ::String?
58
def self.start_if_enabled: () -> bool

spec/datadog/core/telemetry/logging_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,44 @@ def log!(_event)
8282
end
8383
end
8484
end
85+
86+
context 'with ProfilingError' do
87+
before do
88+
skip unless defined?(Datadog::Profiling::ProfilingError)
89+
end
90+
91+
it 'includes the exception message in telemetry' do
92+
expect(component).to receive(:log!).with(instance_of(Datadog::Core::Telemetry::Event::Log)) do |event|
93+
expect(event.payload).to include(
94+
logs: [{message: 'Datadog::Profiling::ProfilingError: (This is a safe profiler error)', level: 'ERROR', count: 1,
95+
stack_trace: a_string_including('REDACTED')}]
96+
)
97+
end
98+
99+
begin
100+
raise Datadog::Profiling::ProfilingError, 'This is a safe profiler error'
101+
rescue => e
102+
component.report(e, level: :error)
103+
end
104+
end
105+
106+
context 'with description' do
107+
it 'includes both description and exception message' do
108+
expect(component).to receive(:log!).with(instance_of(Datadog::Core::Telemetry::Event::Log)) do |event|
109+
expect(event.payload).to include(
110+
logs: [{message: 'Datadog::Profiling::ProfilingError: Profiler failed to start (Failed to initialize native extension)', level: 'ERROR', count: 1,
111+
stack_trace: a_string_including('REDACTED')}]
112+
)
113+
end
114+
115+
begin
116+
raise Datadog::Profiling::ProfilingError, 'Failed to initialize native extension'
117+
rescue => e
118+
component.report(e, level: :error, description: 'Profiler failed to start')
119+
end
120+
end
121+
end
122+
end
85123
end
86124

87125
describe '.error' do

spec/datadog/profiling/collectors/stack_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ def save_rounding_mode # rubocop:disable Lint/UselessMethodDefinition
330330
it do
331331
expect {
332332
sample_and_decode(background_thread, :labels, is_gvl_waiting_state: true)
333-
}.to raise_error(RuntimeError, /BUG: .* is_gvl_waiting/)
333+
}.to raise_error(Datadog::Profiling::ProfilingError, /BUG: .* is_gvl_waiting/)
334334
end
335335
end
336336

@@ -366,7 +366,7 @@ def save_rounding_mode # rubocop:disable Lint/UselessMethodDefinition
366366
let(:metric_values) { {"cpu-samples" => 1} }
367367

368368
it "raises an exception" do
369-
expect { gathered_stack }.to raise_error(RuntimeError, /BUG: Unexpected missing state_label/)
369+
expect { gathered_stack }.to raise_error(Datadog::Profiling::ProfilingError, /BUG: Unexpected missing state_label/)
370370
end
371371
end
372372

spec/datadog/profiling/collectors/thread_context_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,7 +1582,7 @@ def sample_and_check(expected_state:)
15821582

15831583
context "when called before on_gc_start/on_gc_finish" do
15841584
it do
1585-
expect { sample_after_gc(allow_exception: true) }.to raise_error(RuntimeError, /Unexpected call to sample_after_gc/)
1585+
expect { sample_after_gc(allow_exception: true) }.to raise_error(Datadog::Profiling::ProfilingError, /Unexpected call to sample_after_gc/)
15861586
end
15871587
end
15881588

@@ -1601,7 +1601,7 @@ def sample_and_check(expected_state:)
16011601
sample_after_gc
16021602

16031603
expect { sample_after_gc(allow_exception: true) }
1604-
.to raise_error(RuntimeError, /Unexpected call to sample_after_gc/)
1604+
.to raise_error(Datadog::Profiling::ProfilingError, /Unexpected call to sample_after_gc/)
16051605
end
16061606
end
16071607

spec/datadog/profiling/native_extension_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
end
3030

3131
context "when called without releasing the gvl" do
32-
it "raises a RuntimeError" do
32+
it "raises a ProfilingError" do
3333
expect { described_class::Testing._native_grab_gvl_and_raise(ZeroDivisionError, "this is a test", nil, false) }
34-
.to raise_exception(RuntimeError, /called by thread holding the global VM lock/)
34+
.to raise_exception(Datadog::Profiling::ProfilingError, /called by thread holding the global VM lock/)
3535
end
3636
end
3737
end
@@ -58,10 +58,10 @@
5858
end
5959

6060
context "when called without releasing the gvl" do
61-
it "raises a RuntimeError" do
61+
it "raises a ProfilingError" do
6262
expect do
6363
described_class::Testing._native_grab_gvl_and_raise_syserr(Errno::EINTR::Errno, "this is a test", nil, false)
64-
end.to raise_exception(RuntimeError, /called by thread holding the global VM lock/)
64+
end.to raise_exception(Datadog::Profiling::ProfilingError, /called by thread holding the global VM lock/)
6565
end
6666
end
6767
end

spec/datadog/profiling/stack_recorder_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ def introduce_distinct_stacktraces(i, obj)
679679
expect do
680680
Datadog::Profiling::Collectors::Stack::Testing
681681
._native_sample(Thread.current, stack_recorder, metric_values, labels, numeric_labels)
682-
end.to raise_error(RuntimeError, /Ended a heap recording/)
682+
end.to raise_error(Datadog::Profiling::ProfilingError, /Ended a heap recording/)
683683
end
684684

685685
it "does not keep the active slot mutex locked" do
@@ -878,7 +878,7 @@ def sample_and_clear
878878
context "when serialization fails" do
879879
before { expect(described_class).to receive(:_native_serialize).and_return([:error, "test error message"]) }
880880

881-
it { expect { serialize! }.to raise_error(RuntimeError, /test error message/) }
881+
it { expect { serialize! }.to raise_error(Datadog::Profiling::ProfilingError, /test error message/) }
882882
end
883883
end
884884

0 commit comments

Comments
 (0)