diff --git a/lib/datadog/core/telemetry/event.rb b/lib/datadog/core/telemetry/event.rb index 5e62c9cd4cf..15e9a81d848 100644 --- a/lib/datadog/core/telemetry/event.rb +++ b/lib/datadog/core/telemetry/event.rb @@ -346,19 +346,23 @@ def type 'logs' end - def initialize(message:, level:) + def initialize(message:, level:, stack_trace: nil) super() @message = message + @stack_trace = stack_trace @level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" } end def payload { - logs: [{ - message: @message, - level: @level, - # More optional fields to be added here... - }] + logs: [ + { + message: @message, + level: @level, + # More optional fields to be added here... + stack_trace: @stack_trace, + }.compact + ] } end end diff --git a/lib/datadog/core/telemetry/logging.rb b/lib/datadog/core/telemetry/logging.rb index 9d28dcf6ea1..174fc2fe21a 100644 --- a/lib/datadog/core/telemetry/logging.rb +++ b/lib/datadog/core/telemetry/logging.rb @@ -12,6 +12,26 @@ module Telemetry module Logging extend self + # Extract datadog stack trace from the exception + module DatadogStackTrace + REGEX = %r{datadog-.*?/lib/datadog/}.freeze + + def self.from(exception) + return unless exception.backtrace + + stack_trace = +'' + (exception.backtrace || []).each do |line| + stack_trace << if line.match?(REGEX) + line.sub(/^.*?(#{REGEX})/o, '\1') << ',' + else + 'REDACTED,' + end + end + + stack_trace.chomp(',') + end + end + def report(exception, level:, description: nil) # Annoymous exceptions to be logged as message = +'' @@ -20,7 +40,8 @@ def report(exception, level:, description: nil) event = Event::Log.new( message: message, - level: level + level: level, + stack_trace: DatadogStackTrace.from(exception) ) dispatch(event) diff --git a/sig/datadog/core/telemetry/event.rbs b/sig/datadog/core/telemetry/event.rbs index 58f94c5d517..12fd27713c1 100644 --- a/sig/datadog/core/telemetry/event.rbs +++ b/sig/datadog/core/telemetry/event.rbs @@ -72,10 +72,11 @@ module Datadog @message: String @level: "ERROR" | "DEBUG" | "WARN" + @stack_trace: String? - def initialize: (message: String, level: Symbol) -> void + def initialize: (message: String, level: Symbol, ?stack_trace: String?) -> void - def payload: () -> { logs: [{ message: String, level: String }] } + def payload: () -> { logs: [Hash[Symbol, String]] } end class Distributions < GenerateMetrics diff --git a/sig/datadog/core/telemetry/logging.rbs b/sig/datadog/core/telemetry/logging.rbs index 958a0de7b1d..324ac7112c4 100644 --- a/sig/datadog/core/telemetry/logging.rbs +++ b/sig/datadog/core/telemetry/logging.rbs @@ -2,6 +2,11 @@ module Datadog module Core module Telemetry module Logging + module DatadogStackTrace + REGEX: Regexp + def self.from: (Exception exception) -> String? + end + extend Datadog::Core::Telemetry::Logging def report: (Exception exception, level: Symbol, ?description: String?) -> void diff --git a/spec/datadog/core/telemetry/logging_spec.rb b/spec/datadog/core/telemetry/logging_spec.rb index 7b0492fbc73..ad811d742f6 100644 --- a/spec/datadog/core/telemetry/logging_spec.rb +++ b/spec/datadog/core/telemetry/logging_spec.rb @@ -10,7 +10,10 @@ telemetry = instance_double(Datadog::Core::Telemetry::Component) allow(Datadog.send(:components)).to receive(:telemetry).and_return(telemetry) expect(telemetry).to receive(:log!).with(instance_of(Datadog::Core::Telemetry::Event::Log)) do |event| - expect(event.payload).to include(logs: [{ message: 'RuntimeError', level: 'ERROR' }]) + expect(event.payload).to include( + logs: [{ message: 'RuntimeError', level: 'ERROR', + stack_trace: a_string_including('REDACTED') }] + ) end begin @@ -25,7 +28,10 @@ telemetry = instance_double(Datadog::Core::Telemetry::Component) allow(Datadog.send(:components)).to receive(:telemetry).and_return(telemetry) expect(telemetry).to receive(:log!).with(instance_of(Datadog::Core::Telemetry::Event::Log)) do |event| - expect(event.payload).to include(logs: [{ message: 'RuntimeError:Must not contain PII', level: 'ERROR' }]) + expect(event.payload).to include( + logs: [{ message: 'RuntimeError:Must not contain PII', level: 'ERROR', + stack_trace: a_string_including('REDACTED') }] + ) end begin @@ -42,7 +48,10 @@ telemetry = instance_double(Datadog::Core::Telemetry::Component) allow(Datadog.send(:components)).to receive(:telemetry).and_return(telemetry) expect(telemetry).to receive(:log!).with(instance_of(Datadog::Core::Telemetry::Event::Log)) do |event| - expect(event.payload).to include(logs: [{ message: /#