Skip to content

Commit

Permalink
Redis support for sentry-ruby
Browse files Browse the repository at this point in the history
Patches a Redis client to capture breadcrumb and span data when calls
are made to Redis.
  • Loading branch information
lewispb committed Jan 23, 2022
1 parent 9380fbc commit 6862b23
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions sentry-ruby/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gem "rake", "~> 12.0"
gem "rspec", "~> 3.0"
gem "rspec-retry"
gem "webmock"
gem "fakeredis"
gem "timecop"
gem 'simplecov'
gem "simplecov-cobertura", "~> 1.4"
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 @@ -344,3 +344,4 @@ def utc_now

# patches
require "sentry/net/http"
require "sentry/redis/client"
65 changes: 65 additions & 0 deletions sentry-ruby/lib/sentry/redis/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# frozen_string_literal: true

module Sentry
# @api private
module Redis
module Client
OP_NAME = "redis"

def logging(commands, &block)
start_sentry_span.then do |sentry_span|
super.tap do
record_sentry_breadcrumb(commands)
record_sentry_span(commands, sentry_span)
end
end
end

private

def start_sentry_span
return unless Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
return if transaction.sampled == false

transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
end

def record_sentry_breadcrumb(description)
return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:redis_logger)

Sentry.add_breadcrumb(
Sentry::Breadcrumb.new(
level: :info,
category: OP_NAME,
type: :info,
data: {
command: commands.first.first,
key: commands.first.second
}
)
)
end

def record_sentry_span(commands, sentry_span)
return unless Sentry.initialized? && sentry_span

sentry_span.set_description(generate_description(commands))
sentry_span.set_data(:server, server_description)
sentry_span.set_timestamp(Sentry.utc_now.to_f)
end

def generate_description(commands)
commands.first.take(2).join(" ")
end

def server_description
"#{host}:#{port}/#{db}"
end
end
end
end

Sentry.register_patch do
patch = Sentry::Redis
Redis::Client.prepend(Sentry::Redis::Client) unless Redis::Client.ancestors.include?(patch)
end
45 changes: 45 additions & 0 deletions sentry-ruby/spec/sentry/redis/client_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require "spec_helper"
require "fakeredis"

RSpec.describe Sentry::Redis::Client do
let(:string_io) { StringIO.new }
let(:logger) do
::Logger.new(string_io)
end
let(:redis) do
Redis.new
end

context "with tracing enabled" do
before do
perform_basic_setup do |config|
config.traces_sample_rate = 1.0
config.transport.transport_class = Sentry::HTTPTransport
config.logger = logger
# the dsn needs to have a real host so we can make a real connection before sending a failed request
config.dsn = 'http://foobarbaz@o447951.ingest.sentry.io/5434472'
end
end

context "with config.send_default_pii = true" do
before do
Sentry.configuration.send_default_pii = true
end

it "records the request's span with query string" do
transaction = Sentry.start_transaction
Sentry.get_current_scope.set_span(transaction)

redis.set("key", "value")

request_span = transaction.span_recorder.spans.last
expect(request_span.op).to eq("redis")
expect(request_span.start_timestamp).not_to be_nil
expect(request_span.timestamp).not_to be_nil
expect(request_span.start_timestamp).not_to eq(request_span.timestamp)
expect(request_span.description).to eq("set key")
expect(request_span.data).to eq({ server: "127.0.0.1:6379/0" })
end
end
end
end

0 comments on commit 6862b23

Please sign in to comment.