Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
## Unreleased

### Features

- Support for `:origin` attribute in log events ([#2712](https://github.com/getsentry/sentry-ruby/pull/2712))

### Bug Fixes

- Skip including `sentry.message.template` in the log event attributes if there are no interpolation parameters provided ([#2700](https://github.com/getsentry/sentry-ruby/pull/2700))
- Respect `log_level` when logging via `:std_lib_logger` patch ([#2709](https://github.com/getsentry/sentry-ruby/pull/2709))
- Add `sentry.origin` attribute to log events ([#2712](https://github.com/getsentry/sentry-ruby/pull/2712))

## 5.27.0

### Feature
### Features

- Propagated sampling rates as specified in [Traces](https://develop.sentry.dev/sdk/telemetry/traces/#propagated-random-value) docs ([#2671](https://github.com/getsentry/sentry-ruby/pull/2671))
- Support for Rails ActiveSupport log subscribers ([#2690](https://github.com/getsentry/sentry-ruby/pull/2690))
Expand Down
7 changes: 5 additions & 2 deletions sentry-rails/lib/sentry/rails/log_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ module Rails
# end
# end
class LogSubscriber < ActiveSupport::LogSubscriber
ORIGIN = "auto.logger.rails.log_subscriber"

class << self
if ::Rails.version.to_f < 6.0
# Rails 5.x does not provide detach_from
Expand All @@ -51,8 +53,9 @@ def detach_from(namespace, notifications = ActiveSupport::Notifications)
# @param message [String] The log message
# @param level [Symbol] The log level (:trace, :debug, :info, :warn, :error, :fatal)
# @param attributes [Hash] Additional structured attributes to include
def log_structured_event(message:, level: :info, attributes: {})
Sentry.logger.public_send(level, message, **attributes)
# @param origin [String] The origin of the log event
def log_structured_event(message:, level: :info, attributes: {}, origin: ORIGIN)
Sentry.logger.public_send(level, message, **attributes, origin: origin)
rescue => e
# Silently handle any errors in logging to avoid breaking the application
Sentry.configuration.sdk_logger.debug("Failed to log structured event: #{e.message}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
expect(log_event[:attributes][:method][:value]).to eq("GET")
expect(log_event[:attributes][:path][:value]).to eq("/world")
expect(log_event[:attributes][:format][:value]).to eq(:html)
expect(log_event[:attributes]["sentry.origin"][:value]).to eq("auto.logger.rails.log_subscriber")
end

it "logs bad requests appropriately" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
expect(log_event[:attributes][:duration_ms][:value]).to be > 0
expect(log_event[:attributes][:perform_deliveries][:value]).to be true
expect(log_event[:attributes][:delivery_method][:value]).to eq(:test)
expect(log_event[:attributes]["sentry.origin"][:value]).to eq("auto.logger.rails.log_subscriber")
expect(log_event[:attributes][:date]).to be_present
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
expect(log_event[:level]).to eq("info")
expect(log_event[:attributes][:job_class][:value]).to eq("NormalJob")
expect(log_event[:attributes][:duration_ms][:value]).to be > 0
expect(log_event[:attributes]["sentry.origin"][:value]).to eq("auto.logger.rails.log_subscriber")
end

it "logs job enqueue events when jobs are enqueued" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
expect(log_event[:level]).to eq("info")
expect(log_event[:attributes][:sql][:value]).to include("INSERT INTO")
expect(log_event[:attributes][:duration_ms][:value]).to be > 0
expect(log_event[:attributes]["sentry.origin"][:value]).to eq("auto.logger.rails.log_subscriber")
end

it "logs SELECT queries with proper attributes" do
Expand Down
1 change: 1 addition & 0 deletions sentry-ruby/lib/sentry-ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ def capture_check_in(slug, status, **options)
# @param [Hash] options Extra log event options
# @option options [Symbol] level The log level (:trace, :debug, :info, :warn, :error, :fatal)
# @option options [Integer] severity The severity number according to the Sentry Logs Protocol
# @option options [String] origin The origin of the log event (e.g., "auto.db.rails", "manual")
# @option options [Hash] Additional attributes to include with the log
#
# @example Direct usage (prefer using Sentry.logger instead)
Expand Down
5 changes: 3 additions & 2 deletions sentry-ruby/lib/sentry/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ def event_from_check_in(
def event_from_log(message, level:, **options)
return unless configuration.sending_allowed?

attributes = options.reject { |k, _| k == :level || k == :severity }
attributes = options.reject { |k, _| k == :level || k == :severity || k == :origin }
origin = options[:origin]

LogEvent.new(level: level, body: message, attributes: attributes)
LogEvent.new(level: level, body: message, attributes: attributes, origin: origin)
end

# Initializes an Event object with the given Transaction object.
Expand Down
6 changes: 4 additions & 2 deletions sentry-ruby/lib/sentry/log_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class LogEvent
"sentry.address" => :server_name,
"sentry.sdk.name" => :sdk_name,
"sentry.sdk.version" => :sdk_version,
"sentry.message.template" => :template
"sentry.message.template" => :template,
"sentry.origin" => :origin
}

PARAMETER_PREFIX = "sentry.message.parameter"
Expand All @@ -42,7 +43,7 @@ class LogEvent

LEVELS = %i[trace debug info warn error fatal].freeze

attr_accessor :level, :body, :template, :attributes, :user
attr_accessor :level, :body, :template, :attributes, :user, :origin

attr_reader :configuration, *(SERIALIZEABLE_ATTRIBUTES - %i[level body attributes])

Expand Down Expand Up @@ -82,6 +83,7 @@ def initialize(configuration: Sentry.configuration, **options)
@template = @body if is_template?
@attributes = options[:attributes] || DEFAULT_ATTRIBUTES
@user = options[:user] || {}
@origin = options[:origin]
@contexts = {}
end

Expand Down
4 changes: 3 additions & 1 deletion sentry-ruby/lib/sentry/std_lib_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ module StdLibLogger
4 => :fatal
}.freeze

ORIGIN = "auto.logger.ruby.std_logger"

def add(severity, message = nil, progname = nil, &block)
result = super

Expand All @@ -35,7 +37,7 @@ def add(severity, message = nil, progname = nil, &block)
message = message.to_s.strip

if !message.nil? && message != Sentry::Logger::PROGNAME && method = SEVERITY_MAP[severity]
Sentry.logger.send(method, message)
Sentry.logger.send(method, message, origin: ORIGIN)
end
end

Expand Down
1 change: 1 addition & 0 deletions sentry-ruby/spec/isolated/std_lib_logger_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@

expect(log_event[:level]).to eql(level)
expect(log_event[:body]).to eql("Hello World")
expect(log_event[:attributes]["sentry.origin"][:value]).to eq("auto.logger.ruby.std_logger")
end
end
end
Expand Down
36 changes: 36 additions & 0 deletions sentry-ruby/spec/sentry/log_event_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
expect(event.body).to eq("User John has logged in!")
end

it "accepts origin parameter" do
event = described_class.new(
configuration: configuration,
level: :info,
body: "Database query executed",
origin: "auto.db.rails"
)

expect(event.origin).to eq("auto.db.rails")
end

it "accepts attributes" do
attributes = {
"sentry.message.template" => "User %s has logged in!",
Expand Down Expand Up @@ -172,5 +183,30 @@
expect(hash[:attributes]["user.name"]).to eq("john_doe")
expect(hash[:attributes]["user.email"]).to eq("[email protected]")
end

it "includes sentry.origin attribute when origin is set" do
event = described_class.new(
configuration: configuration,
level: :info,
body: "Database query executed",
origin: "auto.db.rails"
)

hash = event.to_hash

expect(hash[:attributes]["sentry.origin"]).to eq({ value: "auto.db.rails", type: "string" })
end

it "does not include sentry.origin attribute when origin is nil" do
event = described_class.new(
configuration: configuration,
level: :info,
body: "Manual log message"
)

hash = event.to_hash

expect(hash[:attributes]).not_to have_key("sentry.origin")
end
end
end
33 changes: 33 additions & 0 deletions sentry-ruby/spec/sentry_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,39 @@
expect(log_event[:trace_id]).to_not be(nil)
expect(log_event[:attributes]).to have_key("sentry.trace.parent_span_id")
end

it "includes sentry.origin attribute when origin is provided" do
expect do
described_class.capture_log("Database query executed", level: :info, origin: "auto.logger.rails.log_subscriber")
end.to_not change { sentry_events.count }

Sentry.get_current_client.flush

expect(sentry_envelopes.count).to eq(1)

log_event = sentry_logs.first

expect(log_event[:level]).to eq("info")
expect(log_event[:body]).to eq("Database query executed")
expect(log_event[:attributes]).to have_key("sentry.origin")
expect(log_event[:attributes]["sentry.origin"]).to eq({ value: "auto.logger.rails.log_subscriber", type: "string" })
end

it "does not include sentry.origin attribute when origin is not provided" do
expect do
described_class.capture_log("Manual log message", level: :info)
end.to_not change { sentry_events.count }

Sentry.get_current_client.flush

expect(sentry_envelopes.count).to eq(1)

log_event = sentry_logs.first

expect(log_event[:level]).to eq("info")
expect(log_event[:body]).to eq("Manual log message")
expect(log_event[:attributes]).not_to have_key("sentry.origin")
end
end

describe ".start_transaction" do
Expand Down
Loading