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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

### Features

- Support for `before_send_log` ([#2634](https://github.com/getsentry/sentry-ruby/pull/2634))

## 5.24.0

### Features
Expand Down
48 changes: 48 additions & 0 deletions sentry-ruby/lib/sentry/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "sentry/transport"
require "sentry/log_event"
require "sentry/log_event_buffer"
require "sentry/utils/uuid"

module Sentry
class Client
Expand Down Expand Up @@ -272,6 +273,53 @@ def send_event(event, hint = nil)
raise
end

# Send an envelope with batched logs
# @param log_events [Array<LogEvent>] the log events to be sent
# @api private
# @return [void]
def send_logs(log_events)
envelope = Envelope.new(
event_id: Sentry::Utils.uuid,
sent_at: Sentry.utc_now.iso8601,
dsn: configuration.dsn,
sdk: Sentry.sdk_meta
)

discarded_count = 0
envelope_items = []

if configuration.before_send_log
log_events.each do |log_event|
processed_log_event = configuration.before_send_log.call(log_event)

if processed_log_event
envelope_items << processed_log_event.to_hash
else
discarded_count += 1
end
end

envelope_items
else
envelope_items = log_events.map(&:to_hash)
end

envelope.add_item(
{
type: "log",
item_count: envelope_items.size,
content_type: "application/vnd.sentry.items.log+json"
},
{ items: envelope_items }
)

send_envelope(envelope)

unless discarded_count.zero?
transport.record_lost_event(:before_send, "log_item", num: discarded_count)
end
end

# Send an envelope directly to Sentry.
# @param envelope [Envelope] the envelope to be sent.
# @return [void]
Expand Down
10 changes: 10 additions & 0 deletions sentry-ruby/lib/sentry/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ class Configuration
# @return [Proc]
attr_reader :before_send_transaction

# Optional Proc, called before sending an event to the server
# @example
# config.before_send_log = lambda do |log|
# log.attributes["sentry"] = true
# log
# end
# @return [Proc]
attr_accessor :before_send_log

# An array of breadcrumbs loggers to be used. Available options are:
# - :sentry_logger
# - :http_logger
Expand Down Expand Up @@ -465,6 +474,7 @@ def initialize

self.before_send = nil
self.before_send_transaction = nil
self.before_send_log = nil
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
self.traces_sampler = nil
self.enable_tracing = nil
Expand Down
24 changes: 1 addition & 23 deletions sentry-ruby/lib/sentry/log_event_buffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ def initialize(configuration, client)
@client = client
@pending_events = []
@max_events = configuration.max_log_events || DEFAULT_MAX_EVENTS
@dsn = configuration.dsn
@sdk = Sentry.sdk_meta
@mutex = Mutex.new

log_debug("[Logging] Initialized buffer with max_events=#{@max_events}, flush_interval=#{FLUSH_INTERVAL}s")
Expand Down Expand Up @@ -70,28 +68,8 @@ def size
private

def send_events
@client.send_envelope(to_envelope)
@client.send_logs(@pending_events)
@pending_events.clear
end

def to_envelope
envelope = Envelope.new(
event_id: SecureRandom.uuid.delete("-"),
sent_at: Sentry.utc_now.iso8601,
dsn: @dsn,
sdk: @sdk
)

envelope.add_item(
{
type: "log",
item_count: size,
content_type: "application/vnd.sentry.items.log+json"
},
{ items: @pending_events.map(&:to_hash) }
)

envelope
end
end
end
6 changes: 3 additions & 3 deletions sentry-ruby/spec/sentry/log_event_buffer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@
end

it "does nothing when the number of events is less than max_events " do
expect(client).to_not receive(:send_envelope)
expect(client).to_not receive(:send_logs)

2.times { log_event_buffer.add_event(log_event) }
end

it "auto-flushes pending events to the client when the number of events reaches max_events" do
expect(client).to receive(:send_envelope)
expect(client).to receive(:send_logs)

3.times { log_event_buffer.add_event(log_event) }

Expand All @@ -60,7 +60,7 @@
let(:max_log_events) { 30 }

it "thread-safely handles concurrent access" do
expect(client).to receive(:send_envelope).exactly(3).times
expect(client).to receive(:send_logs).exactly(3).times

threads = 3.times.map do
Thread.new do
Expand Down
60 changes: 60 additions & 0 deletions sentry-ruby/spec/sentry/structured_logger_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,65 @@
end
end
end

describe "using config.before_send_log" do
let(:transport) do
Sentry.get_current_client.transport
end

before do
perform_basic_setup do |config|
config.enable_logs = true
config.send_client_reports = send_client_reports
config.max_log_events = 1
config.before_send_log = before_send_log
end
end

context "when send_client_reports is turned off and the callback returns a log event" do
let(:send_client_reports) { false }

let(:before_send_log) do
->(log) {
log.attributes["hello"] = "world"
log
}
end

it "sends processed log events" do
Sentry.logger.info("Hello World", user_id: 125, action: "create")
Sentry.logger.info("Hello World", user_id: 123, action: "create")
Sentry.logger.info("Hello World", user_id: 127, action: "create")

expect(sentry_logs.size).to be(3)

log_event = sentry_logs.last

expect(log_event[:attributes]["hello"]).to eql({ value: "world", type: "string" })
end
end

context "when send_client_reports is turned on and the callback returns a log event" do
let(:send_client_reports) { true }

let(:before_send_log) do
->(log) {
if log.attributes[:user_id] == 123
log
end
}
end

it "records discarded events" do
Sentry.logger.info("Hello World", user_id: 125, action: "create")
Sentry.logger.info("Hello World", user_id: 123, action: "create")
Sentry.logger.info("Hello World", user_id: 127, action: "create")

expect(sentry_logs.size).to be(1)

expect(transport.discarded_events).to include([:before_send, "log_item"] => 2)
end
end
end
end
end
Loading